Skip to content

Commit 6babc6f

Browse files
feat: add multipart file upload service
1 parent 4c1da34 commit 6babc6f

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

cmd/server/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func main() {
4141
_, _ = w.Write([]byte("pong"))
4242
}).Methods(http.MethodGet)
4343
r.HandleFunc("/requestbody", requestbody.HandleRequestBody).Methods(http.MethodPost)
44+
r.HandleFunc("/requestbody/multipart-form/files", requestbody.HandleMultipartFormFiles).Methods(http.MethodPost)
4445
r.HandleFunc("/vendorjson", responseHeaders.HandleVendorJsonResponseHeaders).Methods(http.MethodGet)
4546
r.HandleFunc("/pagination/limitoffset/page", pagination.HandleLimitOffsetPage).Methods(http.MethodGet, http.MethodPut)
4647
r.HandleFunc("/pagination/limitoffset/deep_outputs/page", pagination.HandleLimitOffsetDeepOutputsPage).Methods(http.MethodGet, http.MethodPut)

internal/requestbody/service.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package requestbody
22

33
import (
4+
"encoding/base64"
45
"encoding/json"
56
"io"
67
"net/http"
@@ -27,3 +28,76 @@ func HandleRequestBody(w http.ResponseWriter, r *http.Request) {
2728
utils.HandleError(w, err)
2829
}
2930
}
31+
32+
// FileInfo represents information about an uploaded file
33+
type FileInfo struct {
34+
FieldName string `json:"fieldName"`
35+
Filename string `json:"filename"`
36+
Size int64 `json:"size"`
37+
ContentType string `json:"contentType"`
38+
Content string `json:"content,omitempty"` // Base64 encoded content for small files
39+
}
40+
41+
// MultipartFormResponse represents the response for multipart form uploads
42+
type MultipartFormResponse struct {
43+
Files []FileInfo `json:"files"`
44+
FormFields map[string][]string `json:"formFields"`
45+
}
46+
47+
// HandleMultipartFormFiles handles multipart form file uploads
48+
func HandleMultipartFormFiles(w http.ResponseWriter, r *http.Request) {
49+
// Parse multipart form with 32MB max memory
50+
err := r.ParseMultipartForm(32 << 20)
51+
if err != nil {
52+
utils.HandleError(w, err)
53+
return
54+
}
55+
56+
response := MultipartFormResponse{
57+
Files: []FileInfo{},
58+
FormFields: make(map[string][]string),
59+
}
60+
61+
// Handle regular form fields
62+
for key, values := range r.MultipartForm.Value {
63+
response.FormFields[key] = values
64+
}
65+
66+
// Handle file uploads
67+
for fieldName, fileHeaders := range r.MultipartForm.File {
68+
for _, fileHeader := range fileHeaders {
69+
file, err := fileHeader.Open()
70+
if err != nil {
71+
utils.HandleError(w, err)
72+
return
73+
}
74+
defer file.Close()
75+
76+
fileInfo := FileInfo{
77+
FieldName: fieldName,
78+
Filename: fileHeader.Filename,
79+
Size: fileHeader.Size,
80+
ContentType: fileHeader.Header.Get("Content-Type"),
81+
}
82+
83+
// For small files (< 1MB), include base64 encoded content
84+
if fileHeader.Size < 1024*1024 {
85+
content, err := io.ReadAll(file)
86+
if err != nil {
87+
utils.HandleError(w, err)
88+
return
89+
}
90+
// Store as base64 for JSON compatibility
91+
fileInfo.Content = base64.StdEncoding.EncodeToString(content)
92+
}
93+
94+
response.Files = append(response.Files, fileInfo)
95+
}
96+
}
97+
98+
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
99+
100+
if err := json.NewEncoder(w).Encode(response); err != nil {
101+
utils.HandleError(w, err)
102+
}
103+
}

0 commit comments

Comments
 (0)