[ruby] fix: explode object query parameters

Merged
WI
1mo ago
+126-4

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
expectedcategory=books&createdDate%3Agte=2023-01-01
ruby beforefilter%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):

parameteron 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: false keeps its bracket encoding, as on master; the spec wants flatFilter=category,books,….
  • Declared object models ($ref, isModel rather than isMap) still go on the wire whole.
  • A list entry goes out the way ruby sends every array, declared multi arrays included: the encoding is up to the http library and config.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.rb in ruby, ruby-autoload, ruby-faraday and ruby-httpx, from the petstore fixture's language parameter (a declared map with the default style).
  • Technical committee: @meganemura @dkliban @honeyryderchuck

Generated with Claude Code