From b911ccd5f9f8ef0f80826314e3a3fccd224ee97b Mon Sep 17 00:00:00 2001 From: Viacheslav Poturaev Date: Sun, 28 May 2023 11:10:20 +0200 Subject: [PATCH] Fix handling of optional uploads (#160) --- _examples/advanced-generic/file_upload.go | 4 ++++ _examples/go.mod | 4 ++-- _examples/go.sum | 8 +++---- go.mod | 4 ++-- go.sum | 7 +++--- request/file.go | 2 ++ request/file_test.go | 29 ++++++++++++++++++++++- response/encoder.go | 8 ++++--- 8 files changed, 51 insertions(+), 15 deletions(-) diff --git a/_examples/advanced-generic/file_upload.go b/_examples/advanced-generic/file_upload.go index caf37d1..be820a2 100644 --- a/_examples/advanced-generic/file_upload.go +++ b/_examples/advanced-generic/file_upload.go @@ -31,6 +31,10 @@ func fileUploader() usecase.Interactor { u := usecase.NewInteractor(func(ctx context.Context, in upload, out *info) (err error) { out.Query = in.Query out.Simple = in.Simple + if in.Upload1 == nil { + return nil + } + out.Filename = in.Upload1.Filename out.Header = in.Upload1.Header out.Size = in.Upload1.Size diff --git a/_examples/go.mod b/_examples/go.mod index 633ccbb..75268f7 100644 --- a/_examples/go.mod +++ b/_examples/go.mod @@ -7,13 +7,13 @@ replace github.com/swaggest/rest => ../ require ( github.com/bool64/ctxd v1.2.1 github.com/bool64/dev v0.2.27 - github.com/bool64/httpmock v0.1.10 + github.com/bool64/httpmock v0.1.13 github.com/bool64/httptestbench v0.1.4 github.com/go-chi/chi/v5 v5.0.8 github.com/kelseyhightower/envconfig v1.4.0 github.com/rs/cors v1.9.0 github.com/stretchr/testify v1.8.2 - github.com/swaggest/assertjson v1.8.0 + github.com/swaggest/assertjson v1.8.1 github.com/swaggest/jsonschema-go v0.3.51 github.com/swaggest/openapi-go v0.2.30 github.com/swaggest/swgui v1.6.2 diff --git a/_examples/go.sum b/_examples/go.sum index 3fb0541..85de626 100644 --- a/_examples/go.sum +++ b/_examples/go.sum @@ -6,8 +6,8 @@ github.com/bool64/dev v0.2.5/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zR github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/dev v0.2.27 h1:mFT+B74mFVgUeUmm/EbfM6ELPA55lEXBjQ/AOHCwCOc= github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/httpmock v0.1.10 h1:cP+JS+nuIe47uwSheiKtoesziyacxbvWfOVo1zczbek= -github.com/bool64/httpmock v0.1.10/go.mod h1:vodDyrRL4hfWZ6/nvahVzSV4VSK6MSPf0MxyHNQXzuA= +github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo= +github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E= github.com/bool64/httptestbench v0.1.4 h1:35f9RwWqcnQRXM+sA+GUhWVGSa6XEFlKpNSH9oYzOjI= github.com/bool64/httptestbench v0.1.4/go.mod h1:b9ItXGtscs9AcR5oUDnWCTLosQ/DCjiG4euDbHN8T40= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= @@ -55,8 +55,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/swaggest/assertjson v1.8.0 h1:XSg4p6iOZMjtpV2tW2SXfD1GsOOTsWcm+sOADODu/DU= -github.com/swaggest/assertjson v1.8.0/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM= +github.com/swaggest/assertjson v1.8.1 h1:Be2EHY9S2qwKWV+xWZB747Cd7Y79YK6JLdeyrgFvyMo= +github.com/swaggest/assertjson v1.8.1/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM= github.com/swaggest/form/v5 v5.0.4 h1:hTg+gjUEZG0vgsDdXOPi7I0Xu5OowXKoLZIGYZsoddg= github.com/swaggest/form/v5 v5.0.4/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg= github.com/swaggest/jsonschema-go v0.3.51 h1:Cl0hFQ/jtBIP8NlHNuwW6ka3J7zzW5r2jxbLSCUByGY= diff --git a/go.mod b/go.mod index 0c5e4d8..ae3ca16 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.17 require ( github.com/bool64/dev v0.2.27 - github.com/bool64/httpmock v0.1.10 + github.com/bool64/httpmock v0.1.13 github.com/bool64/shared v0.1.5 github.com/cespare/xxhash/v2 v2.2.0 github.com/go-chi/chi/v5 v5.0.8 github.com/santhosh-tekuri/jsonschema/v3 v3.1.0 github.com/stretchr/testify v1.8.2 - github.com/swaggest/assertjson v1.8.0 + github.com/swaggest/assertjson v1.8.1 github.com/swaggest/form/v5 v5.0.4 github.com/swaggest/jsonschema-go v0.3.51 github.com/swaggest/openapi-go v0.2.30 diff --git a/go.sum b/go.sum index 59664dd..65ca5a6 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/bool64/dev v0.2.24/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8 github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/dev v0.2.27 h1:mFT+B74mFVgUeUmm/EbfM6ELPA55lEXBjQ/AOHCwCOc= github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/httpmock v0.1.10 h1:cP+JS+nuIe47uwSheiKtoesziyacxbvWfOVo1zczbek= -github.com/bool64/httpmock v0.1.10/go.mod h1:vodDyrRL4hfWZ6/nvahVzSV4VSK6MSPf0MxyHNQXzuA= +github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo= +github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -68,8 +68,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/swaggest/assertjson v1.8.0 h1:XSg4p6iOZMjtpV2tW2SXfD1GsOOTsWcm+sOADODu/DU= github.com/swaggest/assertjson v1.8.0/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM= +github.com/swaggest/assertjson v1.8.1 h1:Be2EHY9S2qwKWV+xWZB747Cd7Y79YK6JLdeyrgFvyMo= +github.com/swaggest/assertjson v1.8.1/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM= github.com/swaggest/form/v5 v5.0.4 h1:hTg+gjUEZG0vgsDdXOPi7I0Xu5OowXKoLZIGYZsoddg= github.com/swaggest/form/v5 v5.0.4/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg= github.com/swaggest/jsonschema-go v0.3.50/go.mod h1:QfUB5HaZ8y5TiFtCPhM7QwvPNKxTsYxDJaLHTLq6jgU= diff --git a/request/file.go b/request/file.go index 0bd2e38..049f4b0 100644 --- a/request/file.go +++ b/request/file.go @@ -75,6 +75,8 @@ func setFile(r *http.Request, field reflect.StructField, v reflect.Value) error if field.Tag.Get("required") == "true" { return fmt.Errorf("%w: %q", ErrMissingRequiredFile, name) } + + return nil } return fmt.Errorf("failed to get file %q from request: %w", name, err) diff --git a/request/file_test.go b/request/file_test.go index 10c7cfb..09b776f 100644 --- a/request/file_test.go +++ b/request/file_test.go @@ -19,10 +19,12 @@ import ( "github.com/swaggest/rest/openapi" "github.com/swaggest/rest/request" "github.com/swaggest/rest/response" + "github.com/swaggest/rest/web" "github.com/swaggest/usecase" ) type ReqEmb struct { + Simple string `formData:"simple"` UploadHeader *multipart.FileHeader `formData:"upload"` UploadsHeaders []*multipart.FileHeader `formData:"uploads"` } @@ -33,7 +35,32 @@ type fileReqTest struct { Uploads []multipart.File `formData:"uploads"` } -func TestMapper_Decode_fileUploadTag(t *testing.T) { +func TestDecoder_Decode_fileUploadOptional(t *testing.T) { + u := usecase.NewIOI(new(ReqEmb), nil, func(ctx context.Context, input, output interface{}) error { + return nil + }) + + s := web.DefaultService() + s.Post("/", u) + + b := bytes.NewBuffer(nil) + w := multipart.NewWriter(b) + require.NoError(t, w.WriteField("simple", "def")) + require.NoError(t, w.Close()) + + req, err := http.NewRequest(http.MethodPost, "/", b) + require.NoError(t, err) + + req.Header.Set("Content-Type", w.FormDataContentType()) + + rw := httptest.NewRecorder() + s.ServeHTTP(rw, req) + + assert.Equal(t, http.StatusNoContent, rw.Code) + assert.Equal(t, ``, rw.Body.String()) +} + +func TestDecoder_Decode_fileUploadTag(t *testing.T) { r := chirouter.NewWrapper(chi.NewRouter()) apiSchema := openapi.Collector{} decoderFactory := request.NewDecoderFactory() diff --git a/response/encoder.go b/response/encoder.go index ceeda6f..0754809 100644 --- a/response/encoder.go +++ b/response/encoder.go @@ -197,11 +197,13 @@ func (h *Encoder) SetupOutput(output interface{}, ht *rest.HandlerTrait) { func (h *Encoder) successStatus(output interface{}) int { if outputWithStatus, ok := output.(rest.OutputWithHTTPStatus); ok { return outputWithStatus.HTTPStatus() - } else if h.skipRendering && !h.outputWithWriter { + } + + if h.skipRendering && !h.outputWithWriter { return http.StatusNoContent - } else { - return http.StatusOK } + + return http.StatusOK } type jsonEncoder struct {