Repository navigation
Add BindJSONBody to bind the request body value kin-openapi validated - #165
Merged
mromaszewicz merged 2 commits intoOct 23, 2026
Merged
Conversation
Strict net/http servers decode a JSON request body a second time after the
validation middleware has validated it, and encoding/json matches member
names case-insensitively, so a body such as {"role":"user","ROLE":"admin"}
passes validation as role=user and reaches the handler as Role="admin",
bypassing the schema's constraints.
kin-openapi v0.151.0 added openapi3filter.Options.KeepValidatedValue, which
leaves the decoded and validated value on the request body behind a
ValidatedValue() any method. BindJSONBody binds that value into the request
struct when it is present, and otherwise (or when the value does not fit the
destination) falls back to json.NewDecoder(r.Body).Decode as before, so
error behaviour is unchanged.
BindJSONValue does the binding by reflection, following encoding/json's rules
for struct tags, embedded struct promotion, json.Unmarshaler and
encoding.TextUnmarshaler, base64 []byte and float64 for any, with exact
member-name matching. The destination is left untouched when binding fails.
Part of oapi-codegen/oapi-codegen#2605.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 task
Member
Author
|
Consumed by oapi-codegen/oapi-codegen#2612, which switches the strict net/http template to |
golangci-lint flagged two things in the bindJSONAll fixture struct: - staticcheck SA5008 on the `json:"-,"` tag. That tag is intentional: it names the member "-" (the encoding/json documented way to do so), and TestBindJSONValue_FieldCacheIsStable asserts the binder resolves it that way. Keep the tag and silence the check with an explanatory nolint. - unused on the `unexported` field. The field exists so the fixture exercises the binder skipping unexported fields. Reference it with an assertion that it is never set, which both documents the intent and satisfies the linter. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
runtime.BindJSONBody(r *http.Request, v any) errorandruntime.BindJSONValue(value any, v any) error, for the strict net/http server template in oapi-codegen/oapi-codegen#2605.Strict net/http servers decode a JSON request body a second time after the validation middleware has validated it.
encoding/jsonmatches member names case-insensitively, so{"role":"user","ROLE":"admin"}passes validation asrole: userand reaches the handler asRole: "admin", bypassing the schema's constraints.kin-openapi v0.151.0 added
openapi3filter.Options.KeepValidatedValue, which leaves the decoded and validated value onr.Bodybehind aValidatedValue() anymethod.BindJSONBodybinds that value into the request struct when it is present, and otherwise (or when the value does not fit the destination) falls back tojson.NewDecoder(r.Body).Decode(v), so error behaviour, includingio.EOFfor an empty body, is unchanged.BindJSONValuedoes the binding by reflection, followingencoding/json's rules (struct tags, embedded struct promotion and dominance,json.Unmarshaler/encoding.TextUnmarshaler, base64[]byte,float64forany,,string), with one deliberate difference: member names are matched exactly. The destination is left untouched when binding fails.No new dependencies;
go.modstays at Go 1.24.Tests
encoding/jsonand throughBindJSONValueinto a struct covering every field shape oapi-codegen generates (scalars, pointers, slices, arrays, maps with string and int keys,any,json.RawMessage,time.Time,types.Date,types.UUID,types.Email,nullable.Nullable, embedded structs,json:"-",,string) and asserts identical results, including null handling.BindJSONBodytests cover the validated path, the plain path, the fallback after a failed bind (body still readable) andio.EOF.encoding/json(json/v2-backed) andGOEXPERIMENT=nojsonv2.🤖 Generated with Claude Code