Bug Report Checklist
Description
ruby-nextgen sends every object (map) query parameter as name[key]=value, whatever its style/explode. api_operations.mustache puts the Hash under its parameter name (query: { 'filter' => filter }) and Connection hands it to Faraday, which brackets nested hashes. Only style: deepObject comes out right.
style: form, explode: true should put each entry at the top level: ?createdDate:gte=2023-01-01&tld=com
style: form, explode: false should be one comma-separated value: ?flatFilter=tld,com,x,y
openapi-generator version
master, 7.26.0-SNAPSHOT, 05b61f34d7fb0199330e1d6c57e6159f72427837
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: explode
version: 1.0.0
paths:
/things:
get:
operationId: listThings
parameters:
- name: filter
in: query
style: form
explode: true
schema:
type: object
additionalProperties:
type: string
- name: flatFilter
in: query
style: form
explode: false
schema:
type: object
additionalProperties:
type: string
- name: deepFilter
in: query
style: deepObject
explode: true
schema:
type: object
additionalProperties:
type: string
responses:
'200':
description: OK
Generation Details
java -jar openapi-generator-cli.jar generate -g ruby-nextgen -i spec.yaml -o out \
--additional-properties=gemName=petstore,moduleName=Petstore
Generated lib/petstore/api/things.rb:
query: { 'filter' => filter, 'flatFilter' => flat_filter, 'deepFilter' => deep_filter }
Steps to reproduce
$LOAD_PATH.unshift 'out/lib'
require 'petstore'
# Answers every request with 200 and records the url it would have gone out with.
class Capture < Faraday::Middleware
def call(env)
$url = env.url.to_s
env.status = 200; env.body = ''; env.response_headers = Faraday::Utils::Headers.new
env.response = Faraday::Response.new(env)
end
end
client = Petstore::Client.new(base_url: 'http://localhost') { |c| c.use(Capture) }
client.things.list(filter: { 'tld' => 'com', 'createdDate:gte' => '2023-01-01' })
puts URI.decode_www_form_component($url)
client.things.list(flat_filter: { 'tld' => 'com', 'x' => 'y' })
puts URI.decode_www_form_component($url)
client.things.list(deep_filter: { 'tld' => 'com' })
puts URI.decode_www_form_component($url)
Actual (ruby 3.3, faraday 2.14.4):
http://localhost/things?filter[createdDate:gte]=2023-01-01&filter[tld]=com
http://localhost/things?flatFilter[tld]=com&flatFilter[x]=y
http://localhost/things?deepFilter[tld]=com
Expected:
http://localhost/things?createdDate:gte=2023-01-01&tld=com
http://localhost/things?flatFilter=tld,com,x,y
http://localhost/things?deepFilter[tld]=com
Related issues/PRs
Suggest a fix
Spread form/explode maps into the query hash and join form/no-explode maps; deepObject and non-map parameters stay as they are. With this change the snippet above prints the expected output.
--- a/modules/openapi-generator/src/main/resources/ruby-nextgen/api_operations.mustache
+++ b/modules/openapi-generator/src/main/resources/ruby-nextgen/api_operations.mustache
@@ -20,7 +20,7 @@
type: {{{vendorExtensions.x-rb-return-type}}},
auth: [{{#authMethods}}'{{name}}'{{^-last}}, {{/-last}}{{/authMethods}}]{{#hasQueryParams}},{{/hasQueryParams}}{{^hasQueryParams}}{{#hasHeaderParams}},{{/hasHeaderParams}}{{^hasHeaderParams}}{{#bodyParam}},{{/bodyParam}}{{^bodyParam}}{{#hasFormParams}},{{/hasFormParams}}{{/bodyParam}}{{/hasHeaderParams}}{{/hasQueryParams}}
{{#hasQueryParams}}
- query: { {{#queryParams}}'{{baseName}}' => {{paramName}}{{^-last}}, {{/-last}}{{/queryParams}} }{{#hasHeaderParams}},{{/hasHeaderParams}}{{^hasHeaderParams}}{{#bodyParam}},{{/bodyParam}}{{^bodyParam}}{{#hasFormParams}},{{/hasFormParams}}{{/bodyParam}}{{/hasHeaderParams}}
+ query: { {{#queryParams}}{{#isMap}}{{#isExplode}}{{^isDeepObject}}**({{paramName}} || {}){{/isDeepObject}}{{#isDeepObject}}'{{baseName}}' => {{paramName}}{{/isDeepObject}}{{/isExplode}}{{^isExplode}}'{{baseName}}' => {{paramName}}&.to_a&.flatten&.join(','){{/isExplode}}{{/isMap}}{{^isMap}}'{{baseName}}' => {{paramName}}{{/isMap}}{{^-last}}, {{/-last}}{{/queryParams}} }{{#hasHeaderParams}},{{/hasHeaderParams}}{{^hasHeaderParams}}{{#bodyParam}},{{/bodyParam}}{{^bodyParam}}{{#hasFormParams}},{{/hasFormParams}}{{/bodyParam}}{{/hasHeaderParams}}
{{/hasQueryParams}}
{{#hasHeaderParams}}
headers: { {{#headerParams}}'{{baseName}}' => {{paramName}}{{^-last}}, {{/-last}}{{/headerParams}} }{{#bodyParam}},{{/bodyParam}}{{#hasFormParams}},{{/hasFormParams}}
Generated:
query: { **(filter || {}), 'flatFilter' => flat_filter&.to_a&.flatten&.join(','), 'deepFilter' => deep_filter }
Generated with Claude Code
Bug Report Checklist
Description
ruby-nextgensends every object (map) query parameter asname[key]=value, whatever itsstyle/explode.api_operations.mustacheputs the Hash under its parameter name (query: { 'filter' => filter }) andConnectionhands it to Faraday, which brackets nested hashes. Onlystyle: deepObjectcomes out right.style: form, explode: trueshould put each entry at the top level:?createdDate:gte=2023-01-01&tld=comstyle: form, explode: falseshould be one comma-separated value:?flatFilter=tld,com,x,yopenapi-generator version
master, 7.26.0-SNAPSHOT,
05b61f34d7fb0199330e1d6c57e6159f72427837OpenAPI declaration file content or url
Generation Details
Generated
lib/petstore/api/things.rb:Steps to reproduce
Actual (ruby 3.3, faraday 2.14.4):
Expected:
Related issues/PRs
rubygenerator.Suggest a fix
Spread form/explode maps into the query hash and join form/no-explode maps; deepObject and non-map parameters stay as they are. With this change the snippet above prints the expected output.
Generated:
Generated with Claude Code