From 9d64165543332660b708e23f2777be99cc38a2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Sun, 19 Oct 2025 22:16:18 -0400 Subject: [PATCH 1/3] feat: support specifying `encoding` object in request bodies as per https://swagger.io/docs/specification/v3_0/describing-request-body/describing-request-body/#complex-serialization-in-form-data --- openapi/entities.go | 2 ++ operation.go | 40 ++++++++++++++++++++++++++++++++++++++++ option/content.go | 6 ++++++ 3 files changed, 48 insertions(+) diff --git a/openapi/entities.go b/openapi/entities.go index a553b93..9b658a5 100644 --- a/openapi/entities.go +++ b/openapi/entities.go @@ -10,6 +10,8 @@ type ContentUnit struct { IsDefault bool // IsDefault indicates if this content unit is the default response. Description string // Description provides a description for the content unit. + + Encoding map[string]string // Encoding maps property names to content types } // Contact represents contact information for the API. diff --git a/operation.go b/operation.go index d33067c..3ff32ff 100644 --- a/operation.go +++ b/operation.go @@ -8,6 +8,8 @@ import ( specopenapi "github.com/oaswrap/spec/openapi" "github.com/oaswrap/spec/option" "github.com/swaggest/openapi-go" + "github.com/swaggest/openapi-go/openapi3" + "github.com/swaggest/openapi-go/openapi31" ) var _ operationContext = (*operationContextImpl)(nil) @@ -81,6 +83,26 @@ func (oc *operationContextImpl) build() openapi.OperationContext { return oc.op } +func stringMapToEncodingMap3(enc map[string]string) map[string]openapi3.Encoding { + res := map[string]openapi3.Encoding{} + for k, v := range enc { + res[k] = openapi3.Encoding{ + ContentType: &v, + } + } + return res +} + +func stringMapToEncodingMap31(enc map[string]string) map[string]openapi31.Encoding { + res := map[string]openapi31.Encoding{} + for k, v := range enc { + res[k] = openapi31.Encoding{ + ContentType: &v, + } + } + return res +} + func (oc *operationContextImpl) buildRequestOpts(req *specopenapi.ContentUnit) ([]openapi.ContentOption, string) { log := fmt.Sprintf("%T", req.Structure) var opts []openapi.ContentOption @@ -94,6 +116,24 @@ func (oc *operationContextImpl) buildRequestOpts(req *specopenapi.ContentUnit) ( opts = append(opts, openapi.WithContentType(req.ContentType)) log += fmt.Sprintf(" (Content-Type: %s)", req.ContentType) } + opts = append(opts, func(cu *openapi.ContentUnit) { + cu.Customize = func(cor openapi.ContentOrReference) { + switch v := cor.(type) { + case *openapi3.RequestBodyOrRef: + content := map[string]openapi3.MediaType{} + for k, val := range v.RequestBody.Content { + content[k] = *val.WithEncoding(stringMapToEncodingMap3(req.Encoding)) + } + v.RequestBody.WithContent(content) + case *openapi31.RequestBodyOrReference: + content := map[string]openapi31.MediaType{} + for k, val := range v.RequestBody.Content { + content[k] = *val.WithEncoding(stringMapToEncodingMap31(req.Encoding)) + } + v.RequestBody.WithContent(content) + } + } + }) return opts, log } diff --git a/option/content.go b/option/content.go index a4e3fbe..a20f1ad 100644 --- a/option/content.go +++ b/option/content.go @@ -28,3 +28,9 @@ func ContentDefault(isDefault ...bool) ContentOption { cu.IsDefault = util.Optional(true, isDefault...) } } + +func ContentEncoding(prop, enc string) ContentOption { + return func(cu *openapi.ContentUnit) { + cu.Encoding[prop] = enc + } +} \ No newline at end of file From caa171ae4ec533b87393ff830cfbc1266ab6cc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Sun, 19 Oct 2025 22:33:17 -0400 Subject: [PATCH 2/3] fix: ensure we don't assign to a nil map --- option/content.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/option/content.go b/option/content.go index a20f1ad..c84139a 100644 --- a/option/content.go +++ b/option/content.go @@ -31,6 +31,9 @@ func ContentDefault(isDefault ...bool) ContentOption { func ContentEncoding(prop, enc string) ContentOption { return func(cu *openapi.ContentUnit) { + if cu.Encoding == nil { + cu.Encoding = map[string]string{} + } cu.Encoding[prop] = enc } } \ No newline at end of file From 80ffcb708ae7a7ce0ce09ff96bdad0ef28588350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Fri, 24 Oct 2025 14:55:56 -0400 Subject: [PATCH 3/3] style: appease the linter --- operation.go | 6 ++++-- option/content.go | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/operation.go b/operation.go index 3ff32ff..b6089c1 100644 --- a/operation.go +++ b/operation.go @@ -86,8 +86,9 @@ func (oc *operationContextImpl) build() openapi.OperationContext { func stringMapToEncodingMap3(enc map[string]string) map[string]openapi3.Encoding { res := map[string]openapi3.Encoding{} for k, v := range enc { + rv := v res[k] = openapi3.Encoding{ - ContentType: &v, + ContentType: &rv, } } return res @@ -96,8 +97,9 @@ func stringMapToEncodingMap3(enc map[string]string) map[string]openapi3.Encoding func stringMapToEncodingMap31(enc map[string]string) map[string]openapi31.Encoding { res := map[string]openapi31.Encoding{} for k, v := range enc { + rv := v res[k] = openapi31.Encoding{ - ContentType: &v, + ContentType: &rv, } } return res diff --git a/option/content.go b/option/content.go index c84139a..8c93367 100644 --- a/option/content.go +++ b/option/content.go @@ -36,4 +36,4 @@ func ContentEncoding(prop, enc string) ContentOption { } cu.Encoding[prop] = enc } -} \ No newline at end of file +}