[ruby] fix: explode object query parameters
Bug
A query parameter whose schema is an object, with style/explode left at their defaults (form, true), must go on the wire as one parameter per entry, keyed by the property name alone. The ruby client assigned the whole hash under the parameter name, and every http library then bracketed it.
parameters:
- in: query
name: filter
schema:
type: object
called with {"category": "books", "createdDate:gte": "2023-01-01"}:
| on the wire | |
|---|---|
| expected | category=books&createdDate%3Agte=2023-01-01 |
| ruby before | filter%5Bcategory%5D=books&filter%5BcreatedDate%3Agte%5D=2023-01-01 |
Series
One of six per-language PRs for the same bug: #24797 go, #24802 python, #24803 typescript-fetch, #24867 kotlin, #24868 dart, #24869 ruby. No shared main/ code; each adds the same fixture, 3_0/exploded-object-query-param.yaml.
Fix
ruby-client/api.mustache merges an exploded map into query_params entry by entry at the call site, leaving nil entries out, the way nil optional parameters already are:
opts[:'filter'].compact.each { |name, value| query_params[name.to_s] = value } if !opts[:'filter'].nil?
That fixes typhoeus, faraday and httpx at once, since they all consume the query_params hash. deepObject and explode: false parameters, and every other parameter shape, produce the line they did before.
Name collisions. An exploded entry uses a string key where declared parameters use symbols, so on a name clash typhoeus and httpx send both, while faraday (whose params hash is string-keyed) keeps the one assigned last.
Verified
A client generated from the fixture, against a server that echoes its raw query string (typhoeus and faraday give the same result):
| parameter | on the wire |
|---|---|
filter (object, defaults) | category=books&createdDate%3Agte=2023-01-01 |
typedFilter (map, defaults) | category=books&createdDate%3Agte=2023-01-01 |
filter with {"k": nil, "category": "books"} | category=books (without .compact: k= with typhoeus, a bare k with faraday) |
deepFilter (style: deepObject) | deepFilter%5Bcategory%5D=books&… (as on master, and already correct) |
flatFilter (explode: false) | flatFilter%5Bcategory%5D=books&… (as on master, see Known gaps) |
RubyClientCodegenTest#testExplodedObjectQueryParameter fails without the fix.
Known gaps
explode: falsekeeps its bracket encoding, as on master; the spec wantsflatFilter=category,books,….- Declared object models (
$ref,isModelrather thanisMap) still go on the wire whole. - A list entry goes out the way ruby sends every array, declared
multiarrays included: the encoding is up to the http library andconfig.params_encoding(bracketed by default,tld%5B0%5D=com), and so is a nil item inside it.
PR checklist
- Read the contribution guidelines.
- Built the project and updated samples (
./bin/generate-samples.sh bin/configs/ruby*.yaml): 4 files,fake_api.rbin ruby, ruby-autoload, ruby-faraday and ruby-httpx, from the petstore fixture'slanguageparameter (a declared map with the default style). - Technical committee: @meganemura @dkliban @honeyryderchuck
Generated with Claude Code