Skip to content

feat(ruby): let the caller omit an optional request body - #17379

Merged
willkendall01 merged 8 commits into
mainfrom
devin/1786483082-ruby-respect-optional-request-body
Aug 13, 2026
Merged

feat(ruby): let the caller omit an optional request body#17379
willkendall01 merged 8 commits into
mainfrom
devin/1786483082-ruby-respect-optional-request-body

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

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 respectOptionalRequestBody option is on. Previously a bodyless Ruby call still sent {} with Content-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-config seed output is identical to the previously committed root output for that fixture).

Changes Made

  • respectOptionalRequestBody in BaseRubyCustomConfigSchema (Ruby's camelCase config convention), optional/off by default.
  • SDK: when the flag is on and endpoint.requestBody is a reference with required === false, the generated body reference becomes params.empty? ? nil : Types::RefundRequest.new(params).to_h and the request is constructed with omit_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-Type is added only when a body is present:
    sdk_headers = { "Accept" => "application/json" }
    sdk_headers["Content-Type"] = "application/json" unless @omit_content_type_without_body && @body.nil?
    With the flag off, the template renders exactly the previous unconditional hash — no new parameter, no new ivar.
  • Dynamic snippets: bodyRequired === false + an absent/empty example body drops the body keyword arguments entirely (no dangling separator), via callOmitsRequestBody.
  • IR pins bumped to 67.21.0 in all four ruby-v2 packages (dynamic-snippets @fern-api/dynamic-ir-sdk; base/model/sdk @fern-fern/ir-sdk) — see "Dependency pin" below.
  • Seed: respect-optional-request-body fixture now generates two cases (no-custom-config, respect-optional-request-body). The fixture's request schema is a shared $ref used by multiple endpoints, so it stays a reference in the IR (fern ir shows refund -> type: reference, required: false, bulkRefund -> reference/false, requiredRefund -> reference/null), rather than being inlined and making the flag inert.
  • Changelog entry under generators/ruby-v2/sdk/changes/unreleased/.

Dependency pin

@fern-api/dynamic-ir-sdk@67.21.0 / @fern-fern/ir-sdk@67.21.0 are the versions #17360 publishes, and the four ruby-v2 manifests now pin them explicitly — EndpointSnippetGenerator reads dynamic.BodyRequest.bodyRequired and the SDK generator reads HttpRequestBodyReference.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.0 is on npm.buildwithfern.com, but the dynamic-ir job of Release IR SDKs failed for the #17360 commit, so @fern-api/dynamic-ir-sdk@67.21.0 does not exist on npm (latest is 67.12.0) (run 31607788833):

npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/@fern-api%2fdynamic-ir-sdk - Not found
npm error 404  The requested resource '@fern-api/dynamic-ir-sdk@67.21.0' could not be found or you do not have permission to access it.

That job has been failing since 67.12.0 (the same failure is on the previous Release IR SDKs runs), which looks like the publish credential for that package rather than anything in the IR change. Until it publishes, pnpm install cannot resolve the pin, so pnpm-lock.yaml cannot be refreshed and every CI job fails at the frozen-lockfile install — as it does on the other stacked generator PRs that bumped to 67.21.0. tsc over ruby-dynamic-snippets and ruby-sdk against 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:

    case Content-Type body
    flag on, bulk_refund no body absent none (no Content-Length)
    flag on, bulk_refund with body application/json {"amount":60}
    flag on, refund (path param only, no body) absent none
    flag on, refund (path param + body) application/json {"amount":60}
    flag on, required_refund (required body) application/json {} (unchanged)
    flag off, every case above application/json {} / {"amount":60} (unchanged)

Link to Devin session: https://app.devin.ai/sessions/a0178cce544c4a51ba568b0fc7c8b5fa


Open in Devin Review

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes — everything looks good. No issues found.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread generators/ruby-v2/sdk/src/endpoint/request/EndpointRequest.ts
Base automatically changed from feat/ir-request-body-required to main August 12, 2026 14:37
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786483082-ruby-respect-optional-request-body branch from 5bcdfb9 to 69999e2 Compare August 12, 2026 14:39
devin-ai-integration Bot and others added 3 commits August 12, 2026 15:26
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)
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786483082-ruby-respect-optional-request-body branch from 69999e2 to c3f666a Compare August 12, 2026 15:28
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-08-13T04:34:37Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
ruby-sdk-v2 square 106s (n=5) 147s (n=5) 88s -18s (-17.0%)

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 fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-08-13T04:34:37Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-08-13 17:06 UTC

willkendall01 and others added 2 commits August 12, 2026 17:06
… 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>
willkendall01 and others added 2 commits August 13, 2026 15:51
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@willkendall01
willkendall01 merged commit e91ee5d into main Aug 13, 2026
83 checks passed
@willkendall01
willkendall01 deleted the devin/1786483082-ruby-respect-optional-request-body branch August 13, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants