diff --git a/docs/content/reference/scalars.md b/docs/content/reference/scalars.md index 7b098b06896..2cf127f295c 100644 --- a/docs/content/reference/scalars.md +++ b/docs/content/reference/scalars.md @@ -35,7 +35,7 @@ scalar Upload Maps a `Upload` GraphQL scalar to a `graphql.Upload` struct, defined as follows: ``` type Upload struct { - File multipart.File + FileData []byte Filename string Size int64 } diff --git a/example/fileupload/fileupload_test.go b/example/fileupload/fileupload_test.go index e91029375f9..3ad3444a5f7 100644 --- a/example/fileupload/fileupload_test.go +++ b/example/fileupload/fileupload_test.go @@ -23,15 +23,13 @@ func TestFileUpload(t *testing.T) { resolver := &Resolver{ SingleUploadFunc: func(ctx context.Context, file graphql.Upload) (*model.File, error) { require.NotNil(t, file) - require.NotNil(t, file.File) - content, err := ioutil.ReadAll(file.File) - require.Nil(t, err) - require.Equal(t, string(content), "test") + require.NotNil(t, file.FileData) + require.Equal(t, string(file.FileData), "test") return &model.File{ ID: 1, Name: file.Filename, - Content: string(content), + Content: string(file.FileData), }, nil }, } @@ -66,15 +64,13 @@ func TestFileUpload(t *testing.T) { SingleUploadWithPayloadFunc: func(ctx context.Context, req model.UploadFile) (*model.File, error) { require.Equal(t, req.ID, 1) require.NotNil(t, req.File) - require.NotNil(t, req.File.File) - content, err := ioutil.ReadAll(req.File.File) - require.Nil(t, err) - require.Equal(t, string(content), "test") + require.NotNil(t, req.File.FileData) + require.Equal(t, string(req.File.FileData), "test") return &model.File{ ID: 1, Name: req.File.Filename, - Content: string(content), + Content: string(req.File.FileData), }, nil }, } @@ -110,14 +106,12 @@ func TestFileUpload(t *testing.T) { var contents []string var resp []model.File for i := range files { - require.NotNil(t, files[i].File) - content, err := ioutil.ReadAll(files[i].File) - require.Nil(t, err) - contents = append(contents, string(content)) + require.NotNil(t, files[i].FileData) + contents = append(contents, string(files[i].FileData)) resp = append(resp, model.File{ ID: i + 1, Name: files[i].Filename, - Content: string(content), + Content: string(files[i].FileData), }) } require.ElementsMatch(t, []string{"test1", "test2"}, contents) @@ -163,15 +157,13 @@ func TestFileUpload(t *testing.T) { var resp []model.File for i := range req { require.NotNil(t, req[i].File) - require.NotNil(t, req[i].File.File) - content, err := ioutil.ReadAll(req[i].File.File) - require.Nil(t, err) + require.NotNil(t, req[i].File.FileData) ids = append(ids, req[i].ID) - contents = append(contents, string(content)) + contents = append(contents, string(req[i].File.FileData)) resp = append(resp, model.File{ ID: i + 1, Name: req[i].File.Filename, - Content: string(content), + Content: string(req[i].File.FileData), }) } require.ElementsMatch(t, []int{1, 2}, ids) @@ -218,16 +210,13 @@ func TestFileUpload(t *testing.T) { var resp []model.File for i := range req { require.NotNil(t, req[i].File) - require.NotNil(t, req[i].File.File) + require.NotNil(t, req[i].File.FileData) ids = append(ids, req[i].ID) - req[i].File.File.Seek(0, 0) - content, err := ioutil.ReadAll(req[i].File.File) - require.Nil(t, err) - contents = append(contents, string(content)) + contents = append(contents, string(req[i].File.FileData)) resp = append(resp, model.File{ ID: i + 1, Name: req[i].File.Filename, - Content: string(content), + Content: string(req[i].File.FileData), }) } require.ElementsMatch(t, []int{1, 2}, ids) diff --git a/example/fileupload/server/server.go b/example/fileupload/server/server.go index fdc72aab812..9f7888f4747 100644 --- a/example/fileupload/server/server.go +++ b/example/fileupload/server/server.go @@ -3,7 +3,6 @@ package main import ( "context" "errors" - "io/ioutil" "log" "net/http" @@ -30,25 +29,17 @@ func main() { func getResolver() *fileupload.Resolver { resolver := &fileupload.Resolver{ SingleUploadFunc: func(ctx context.Context, file graphql.Upload) (*model.File, error) { - content, err := ioutil.ReadAll(file.File) - if err != nil { - return nil, err - } return &model.File{ ID: 1, Name: file.Filename, - Content: string(content), + Content: string(file.FileData), }, nil }, SingleUploadWithPayloadFunc: func(ctx context.Context, req model.UploadFile) (*model.File, error) { - content, err := ioutil.ReadAll(req.File.File) - if err != nil { - return nil, err - } return &model.File{ ID: 1, Name: req.File.Filename, - Content: string(content), + Content: string(req.File.FileData), }, nil }, MultipleUploadFunc: func(ctx context.Context, files []graphql.Upload) ([]model.File, error) { @@ -57,14 +48,10 @@ func getResolver() *fileupload.Resolver { } var resp []model.File for i := range files { - content, err := ioutil.ReadAll(files[i].File) - if err != nil { - return []model.File{}, err - } resp = append(resp, model.File{ ID: i + 1, Name: files[i].Filename, - Content: string(content), + Content: string(files[i].FileData), }) } return resp, nil @@ -75,14 +62,10 @@ func getResolver() *fileupload.Resolver { } var resp []model.File for i := range req { - content, err := ioutil.ReadAll(req[i].File.File) - if err != nil { - return []model.File{}, err - } resp = append(resp, model.File{ ID: i + 1, Name: req[i].File.Filename, - Content: string(content), + Content: string(req[i].File.FileData), }) } return resp, nil diff --git a/graphql/upload.go b/graphql/upload.go index e7919f1b415..1b01bc6891c 100644 --- a/graphql/upload.go +++ b/graphql/upload.go @@ -3,18 +3,17 @@ package graphql import ( "fmt" "io" - "mime/multipart" ) type Upload struct { - File multipart.File + FileData []byte Filename string Size int64 } func MarshalUpload(f Upload) Marshaler { return WriterFunc(func(w io.Writer) { - io.Copy(w, f.File) + w.Write(f.FileData) }) } diff --git a/handler/graphql.go b/handler/graphql.go index e34329a8f05..db128f11d37 100644 --- a/handler/graphql.go +++ b/handler/graphql.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "net/http" "strconv" "strings" @@ -563,11 +564,16 @@ func processMultipart(w http.ResponseWriter, r *http.Request, request *params, u if err != nil { return fmt.Errorf("failed to get key %s from form", key) } + defer file.Close() if len(paths) == 0 { return fmt.Errorf("invalid empty operations paths list for key %s", key) } + fileData, err := ioutil.ReadAll(file) + if err != nil { + return fmt.Errorf("failed to read file for key %s", key) + } upload = graphql.Upload{ - File: file, + FileData: fileData, Size: header.Size, Filename: header.Filename, } diff --git a/handler/graphql_test.go b/handler/graphql_test.go index fd353cff1b8..50c9bd74b86 100644 --- a/handler/graphql_test.go +++ b/handler/graphql_test.go @@ -8,7 +8,6 @@ import ( "mime/multipart" "net/http" "net/http/httptest" - "os" "strings" "testing" @@ -425,9 +424,8 @@ func TestProcessMultipart(t *testing.T) { require.True(t, ok) require.Equal(t, "a.txt", reqParamsFile.Filename) require.Equal(t, int64(len("test1")), reqParamsFile.Size) - content, err := ioutil.ReadAll(reqParamsFile.File) require.Nil(t, err) - require.Equal(t, "test1", string(content)) + require.Equal(t, "test1", string(reqParamsFile.FileData)) }) t.Run("valid request with two values", func(t *testing.T) { @@ -459,11 +457,8 @@ func TestProcessMultipart(t *testing.T) { file := itemMap["file"].(graphql.Upload) require.Equal(t, "a.txt", file.Filename) require.Equal(t, int64(len("test1")), file.Size) - _, err = file.File.Seek(0, 0) require.Nil(t, err) - content, err := ioutil.ReadAll(file.File) - require.Nil(t, err) - require.Equal(t, "test1", string(content)) + require.Equal(t, "test1", string(file.FileData)) } }) } @@ -471,11 +466,10 @@ func TestProcessMultipart(t *testing.T) { func TestAddUploadToOperations(t *testing.T) { t.Run("fail missing all variables", func(t *testing.T) { - file, _ := os.Open("path/to/file") request := ¶ms{} upload := graphql.Upload{ - File: file, + FileData: []byte{}, Filename: "a.txt", Size: int64(5), } @@ -486,7 +480,6 @@ func TestAddUploadToOperations(t *testing.T) { }) t.Run("valid variable", func(t *testing.T) { - file, _ := os.Open("path/to/file") request := ¶ms{ Variables: map[string]interface{}{ "file": nil, @@ -494,7 +487,7 @@ func TestAddUploadToOperations(t *testing.T) { } upload := graphql.Upload{ - File: file, + FileData: []byte{}, Filename: "a.txt", Size: int64(5), } @@ -513,7 +506,6 @@ func TestAddUploadToOperations(t *testing.T) { }) t.Run("valid nested variable", func(t *testing.T) { - file, _ := os.Open("path/to/file") request := ¶ms{ Variables: map[string]interface{}{ "req": []interface{}{ @@ -525,7 +517,7 @@ func TestAddUploadToOperations(t *testing.T) { } upload := graphql.Upload{ - File: file, + FileData: []byte{}, Filename: "a.txt", Size: int64(5), }