Repository navigation
This release adds a request body binder that reuses the value a kin-openapi validation middleware already decoded, so strict servers no longer decode the body a second time with different matching rules. It also rounds out types.Date's text encoding and fixes a deepObject serialization quirk. Existing binding and serialization behaviour is unchanged unless generated code calls the new function. The root module's dependencies are unchanged; the separate strictmiddleware/echo-v5 module now requires Echo v5.4.2.
Notable Changes
BindJSONBody: bind exactly what the validator validated
Strict servers generated by oapi-codegen decode the JSON request body with encoding/json after a validation middleware has already decoded and validated it. The two decoders do not agree on member names: encoding/json matches struct fields case-insensitively, so a body like {"role":"user","ROLE":"admin"} validates as role: user and then binds as Role: "admin". Anything the validator checked can be bypassed by a differently-cased duplicate.
BindJSONBody(r *http.Request, v any) error closes that gap. When the request has passed through a validator built on kin-openapi v0.151.0 or later with openapi3filter.Options.KeepValidatedValue set, the body carries the value the validator decoded, and BindJSONBody binds that value into the destination with BindJSONValue(value, v any) error instead of reading the body again. Binding follows encoding/json's rules (struct tags, embedded structs, json.Unmarshaler and encoding.TextUnmarshaler, base64 for []byte, float64 for any, json.Number preserved) with one deliberate difference: member names are matched to struct fields exactly.
Without a validated value, or when the value cannot be bound into the destination type, BindJSONBody falls back to json.NewDecoder(r.Body).Decode(v), so error responses are unchanged for everyone who is not running a validator. The oapi-codegen validation middlewares enable KeepValidatedValue by default as of nethttp-middleware v1.3.1, echo-middleware v1.2.1, echo-v5-middleware v0.2.1, gin-middleware v1.2.1 and iris-middleware v1.2.1. The net/http strict server template that calls BindJSONBody is landing in oapi-codegen separately (oapi-codegen/oapi-codegen#2605); the runtime side ships first so generated code can rely on it.
types.Date implements encoding.TextMarshaler
Date had an UnmarshalText that parses 2006-01-02 but no MarshalText, so it inherited time.Time's RFC 3339 one. Any codec that pairs TextMarshaler with TextUnmarshaler (encoding/xml, DynamoDB mappers, and others) therefore wrote a Date it could not read back. MarshalText now formats with DateFormat, matching MarshalJSON, String and UnmarshalText. Thanks to @jusabe-kreditz.
deepObject no longer emits param[]=null for nil maps and slices
Marshalling a deepObject parameter whose field held a typed nil map or nil slice produced a param[]=null pair, because the intermediate json.Marshal turned the nil into null. Such fields are now omitted, as an empty map or slice already was. Nil pointers are still serialized as null, as before. Thanks to @SKalt (#160).
🚀 New features and improvements
- Add BindJSONBody to bind the request body value kin-openapi validated (#165) @mromaszewicz
- Add MarshalText to types.Date (#162) @jusabe-kreditz, @mromaszewicz
🐛 Bug fixes
- fix: omit nil maps and slices from deepObject marshalling (#161) @SKalt, @mromaszewicz
📦 Dependency updates
6 changes
- fix(deps): update module github.com/labstack/echo/v5 to v5.4.2 (#166) @renovate[bot]
- chore(deps): update release-drafter/release-drafter action to v7.10.0 (#164) @renovate[bot]
- fix(deps): update module github.com/labstack/echo/v5 to v5.4.1 (#163) @renovate[bot]
- chore(deps): update github/codeql-action action to v4.39.1 (#159) @renovate[bot]
- chore(deps): update oapi-codegen/actions action to v0.9.2 (#158) @renovate[bot]
- chore(deps): update module github.com/golangci/golangci-lint to v2.15.0 (#157) @renovate[bot]
Sponsors
We would like to thank our sponsors for their support during this release.
New contributors
- @jusabe-kreditz made their first contribution in #162
- @SKalt made their first contribution in #161