Query decoding
In this library, decoding a query means converting its OpenAPI wire format into validated JSON.
OpenAPI query parameters combine styles such as form, spaceDelimited, pipeDelimited, and deepObject with explode, repeated names, scalar conversion, and bracketed names. The OpenAPI 3.0.3 Parameter Object shows how much the wire shape changes between combinations.
One output format
Section titled “One output format”Given a deepObject parameter named filter:
filter[role]=admin&filter[active]=trueQueryDecoder.Decode returns:
{"filter":{"active":true,"role":"admin"}}OpenAPI 3.0.3 does not define how deepObject serializes array-valued object properties. Klopt extends the OpenAPI behavior with repeated bracketed keys:
- name: tags in: query style: deepObject explode: true schema: type: object properties: key: type: array items: type: stringtags[key]=item1&tags[key]=item2decodes to:
{"tags":{"key":["item1","item2"]}}Use that JSON with any struct:
raw, err := requestValidations["listThings"].Query.Decode(r.URL)if err != nil { return err}
var query ListThingsQueryif err := json.Unmarshal(raw, &query); err != nil { return err}Or pass it to json.Decoder after validation. Callers only need to handle JSON; the OpenAPI style rules stay inside the query decoder.
Why not url.Values
Section titled “Why not url.Values”OpenAPI delimiters must be read before ordinary percent-decoding:
ids=a%2Cb,c → ["a,b", "c"]ids=a,b,c → ["a", "b", "c"]In the first query, the encoded comma belongs to the first string. The raw comma separates array items. After decoding into url.Values, both values look like a,b,c, so that information is gone.
QueryDecoder therefore reads URL.RawQuery, claims names against the compiled parameters, applies style and explode, converts scalar types, and validates the resulting JSON value.
Trade-off
Section titled “Trade-off”A caller may decode the returned JSON into a Go struct, which means creating JSON and decoding it again. That extra work is accepted deliberately. A single familiar format, user-chosen structs, and fewer wire-decoding bugs matter more here than avoiding one intermediate representation.