Skip to content

fix(openapi): preserve 204 status code in response conversion#14982

Open
devin-ai-integration[bot] wants to merge 4 commits intomainfrom
devin/1776182821-fix-204-status-code
Open

fix(openapi): preserve 204 status code in response conversion#14982
devin-ai-integration[bot] wants to merge 4 commits intomainfrom
devin/1776182821-fix-204-status-code

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Apr 14, 2026

Description

Fixes a bug where a 204 No Content status code defined in an OpenAPI spec is displayed as "200 Successful" in Fern docs. The status code was being lost during the OpenAPI → Fern IR conversion because no-body responses produced undefined in the response field, and downstream defaults filled in 200.

This also affects other non-200 success codes (201, 202) when the endpoint has no response body.

Changes Made

Three files in the OpenAPI importer pipeline are modified:

  1. convertResponse.ts — Added a successStatusCode field to ConvertedResponse that tracks the first success status code encountered, even when the response has no body (i.e., value is undefined).

  2. convertHttpOperation.ts — When convertedResponse.value is undefined but successStatusCode is non-200, creates a ResponseWithExample.text() carrier to propagate the status code through the IR.

  3. buildEndpoint.ts — In the text response handler, special-cases statusCode === 204 to emit only "status-code": 204 in the Fern Definition without setting type: "text", so the downstream IR correctly represents a no-body response.

Additionally:

  • Added a no-content seed test fixture (test-definitions/fern/apis/no-content/) with an OpenAPI spec containing a DELETE endpoint returning 204
  • Generated ts-sdk seed output for the new fixture
  • Added an unreleased changelog entry
  • Updated snapshots across multiple test suites (openapi-ir-to-fern-tests, v3-importer-tests, ir-to-jsonschema, ete-tests)

⚠️ Reviewer Checklist

  • Carrier response approach: The fix uses ResponseWithExample.text() as a "carrier" to thread the status code through the OpenAPI IR (which doesn't have a dedicated "no body" response variant). Confirm this doesn't cause unexpected behavior in other consumers of the IR.
  • Hardcoded 204 in buildEndpoint.ts: The textResponse.statusCode === 204 check is specific to 204. Other non-200 codes with no body (e.g., 201) will still get type: "text" set in the Fern Definition. Consider whether this should be more general (e.g., checking for absence of actual text content). The ete-test snapshots show this: petstore's createPets (201) now gets status-code: 201 with type: text, while 204 endpoints get only status-code: 204.
  • Snapshot changes: Examples are removed from endpoints that now have carrier text responses (e.g., hathora's delete/destroy/suspend endpoints, file-upload's create conversation). Verify this is acceptable behavior.
  • Downstream pipeline: This fix ensures status code reaches the Fern IR, but fern-platform's v1ToV2.ts migrator also has statusCode ?? 200 and an early return undefined when response.type == null. A separate fix there may be needed for full end-to-end correctness after re-running fern generate --docs.
  • Other generators: Only ts-sdk seed output was generated. Verify whether other generators also need seed output for this fixture.

Testing

  • Seed test (ts-sdk) passes for the new no-content fixture
  • pnpm compile passes for affected packages
  • pnpm run check (biome) passes cleanly
  • All CI checks pass (260/260)

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

Co-Authored-By: rishabh <rishabh@buildwithfern.com>
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@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 and CI monitoring

@github-actions
Copy link
Copy Markdown
Contributor

🌱 Seed Test Selector

Select languages to run seed tests for:

  • Python
  • TypeScript
  • Java
  • Go
  • Ruby
  • C#
  • PHP
  • Swift
  • Rust
  • OpenAPI

How to use: Click the ⋯ menu above → "Edit" → check the boxes you want → click "Update comment". Tests will run automatically and snapshots will be committed to this PR.

devin-ai-integration bot and others added 3 commits April 14, 2026 16:29
Co-Authored-By: rishabh <rishabh@buildwithfern.com>
Co-Authored-By: rishabh <rishabh@buildwithfern.com>
Co-Authored-By: rishabh <rishabh@buildwithfern.com>
@github-actions
Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against latest nightly baseline on main (2026-04-14T04:55:49Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 92s 127s 86s -6s (-6.5%)
go-sdk square 90s 137s 107s +17s (+18.9%)
java-sdk square 173s 187s 168s -5s (-2.9%)
php-sdk square 84s 122s 85s +1s (+1.2%)
python-sdk square 128s 163s 128s +0s (+0.0%)
ruby-sdk-v2 square 113s 156s 133s +20s (+17.7%)
rust-sdk square 96s 92s 100s +4s (+4.2%)
swift-sdk square 86s 129s 84s -2s (-2.3%)
ts-sdk square 101s 136s 96s -5s (-5.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-04-14T04:55:49Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-04-14 16:59 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

0 participants