feat(ruby): let the caller omit an optional request body - #17379
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
5bcdfb9 to
69999e2
Compare
Add a respectOptionalRequestBody option, off by default. When it is on and the IR marks a referenced request body as optional, a call that passes no body properties sends neither a body nor a Content-Type header. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: bot_apk <apk@cognition.ai> (cherry picked from commit bbb068a)
Co-Authored-By: bot_apk <apk@cognition.ai> (cherry picked from commit c51b063)
…ttability Co-Authored-By: bot_apk <apk@cognition.ai> (cherry picked from commit 69999e2)
69999e2 to
c3f666a
Compare
SDK Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
… the new IR Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Description
Linear ticket: Refs
Ruby parity for IR request-body omittability (#17360 has merged, so this now targets
main; alongside #17372 Java, #17370 Python, #17368 TS, #17373 C#, #17378 Go, #17380 PHP).A referenced request body that the API does not mark required is now omittable by the caller when the new
respectOptionalRequestBodyoption is on. Previously a bodyless Ruby call still sent{}withContent-Type: application/json— the Payabli over-refund shape, where the docs snippet looks bodyless but the SDK sends a body.The option is off by default, so existing output is byte-identical (the
respect-optional-request-body/no-custom-configseed output is identical to the previously committed root output for that fixture).Changes Made
respectOptionalRequestBodyinBaseRubyCustomConfigSchema(Ruby's camelCase config convention), optional/off by default.endpoint.requestBodyis areferencewithrequired === false, the generated body reference becomesparams.empty? ? nil : Types::RefundRequest.new(params).to_hand the request is constructed withomit_content_type_without_body: true. Form-urlencoded bodies are excluded (their template always emits a form content type).internal/json/request.rb(templated): under the flag,Content-Typeis added only when a body is present:bodyRequired === false+ an absent/empty example body drops the body keyword arguments entirely (no dangling separator), viacallOmitsRequestBody.67.21.0in all four ruby-v2 packages (dynamic-snippets@fern-api/dynamic-ir-sdk;base/model/sdk@fern-fern/ir-sdk) — see "Dependency pin" below.respect-optional-request-bodyfixture now generates two cases (no-custom-config,respect-optional-request-body). The fixture's request schema is a shared$refused by multiple endpoints, so it stays a reference in the IR (fern irshowsrefund -> type: reference, required: false,bulkRefund -> reference/false,requiredRefund -> reference/null), rather than being inlined and making the flag inert.generators/ruby-v2/sdk/changes/unreleased/.Dependency pin
@fern-api/dynamic-ir-sdk@67.21.0/@fern-fern/ir-sdk@67.21.0are the versions #17360 publishes, and the four ruby-v2 manifests now pin them explicitly —EndpointSnippetGeneratorreadsdynamic.BodyRequest.bodyRequiredand the SDK generator readsHttpRequestBodyReference.required, neither of which exists in the previous pins (66.1.0/67.15.0), with no casts or suppressions.Blocked on the IR release pipeline, not on this PR.
@fern-fern/ir-sdk@67.21.0is onnpm.buildwithfern.com, but thedynamic-irjob ofRelease IR SDKsfailed for the #17360 commit, so@fern-api/dynamic-ir-sdk@67.21.0does not exist on npm (latest is67.12.0) (run 31607788833):That job has been failing since
67.12.0(the same failure is on the previousRelease IR SDKsruns), which looks like the publish credential for that package rather than anything in the IR change. Until it publishes,pnpm installcannot resolve the pin, sopnpm-lock.yamlcannot be refreshed and every CI job fails at the frozen-lockfile install — as it does on the other stacked generator PRs that bumped to67.21.0.tscoverruby-dynamic-snippetsandruby-sdkagainst the new field definitions passes cleanly.Testing
Unit tests added/updated —
generators/ruby-v2/dynamic-snippets/src/__test__/OptionalRequestBody.test.ts(35 tests pass in that package); ruby-sdk tests pass.Seed:
pnpm seed test --generator ruby-sdk-v2 --skip-scripts --local→ 150/150; only the new fixture output changed.Manual testing completed — wire capture of the generated SDK (Ruby 3.3 in Docker) against a local HTTP server that echoes the request line, headers and body:
bulk_refundno bodyContent-Length)bulk_refundwith bodyapplication/json{"amount":60}refund(path param only, no body)refund(path param + body)application/json{"amount":60}required_refund(required body)application/json{}(unchanged)application/json{}/{"amount":60}(unchanged)Link to Devin session: https://app.devin.ai/sessions/a0178cce544c4a51ba568b0fc7c8b5fa