Skip to content

fix(swift): build wire-test JSON body from typed example shape#15687

Open
devin-ai-integration[bot] wants to merge 1 commit intomainfrom
devin/1777932554-swift-wire-test-dict-null-mismatch
Open

fix(swift): build wire-test JSON body from typed example shape#15687
devin-ai-integration[bot] wants to merge 1 commit intomainfrom
devin/1777932554-swift-wire-test-dict-null-mismatch

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

Description

Linear ticket: Closes FER-10341

Fixes 7 Swift wire-test runtime equality failures observed in the latest nightly Square baseline-e2e runOrdersClient.{updateOrder2,payOrder2,calculateOrder2,cloneOrder2,retrieveOrder2,createOrder2} and CheckoutClient.createPaymentLink2.

Root cause

When a wire-test response body contains a Dictionary<String, T> whose value is an explicit-null Nullable<T>, the typed example shape stored on ExampleTypeReference retains the entry (mapContainer.map has a key whose value is a Container.nullable with nullable: undefined), but the IR's parallel jsonExample projection ends up with the value as JS undefined. JSON.stringify then silently drops the key from the embedded JSON body. The expected response struct, however, is built by walking the typed shape (Nullable<T>.null is preserved), so JSONDecoder.decode(...) produces [:] while the expected struct contains ["metadata": .null], and the runtime equality assertion fails:

LHS (decoded):  Nullable<Dictionary<String, Nullable<String>>>.value([:])
RHS (expected): Nullable<Dictionary<String, Nullable<String>>>.value(["metadata": Nullable.null])

Fix

Build the wire-test JSON body by walking the typed ExampleTypeReference shape directly, the same source the expected struct is built from. This keeps the two sides in sync by construction. Discriminated and undiscriminated unions (whose wire format requires type-declaration metadata not present on the example shape) fall back to the IR-supplied jsonExample, since the map-with-null-entries asymmetry does not apply within union examples.

Changes Made

  • New helper buildJsonFromExampleTypeReference (in generators/swift/sdk/src/generators/test/) walks ExampleTypeReference.shape and produces a JSON-encodable JS value mirroring the wire format. Maps with explicit-null entries surface as null (not undefined) so they survive JSON.stringify.
  • WireTestFunctionGenerator now routes the embedded response body through this helper instead of JSON.stringify(exampleTypeRef.jsonExample, null, 2). Existing raw-string fast path (used for the iCalendar fixture from fix(swift): emit wire-test response bodies as raw multi-line string literals #15605) is preserved.

Testing

  • Unit tests added/updated — 7 new cases in buildJsonFromExampleTypeReference.test.ts covering primitives, populated and unset nullables, optionals, lists with nullable<T> items, the regression case of map<string, nullable<string>> with an explicit-null entry, and a nested-object containing such a map.
  • All swift-sdk unit tests pass locally (20/20).
  • CI to verify against Square baseline-e2e (the original failing fixture).

Local seed verification was not feasible because pnpm seed:build is currently broken on main due to an unrelated @fern-api/register TypeScript compile error against the pinned @fern-api/fdr-sdk (Availability enum missing Legacy/Alpha/Preview variants).

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

When a Swift wire-test response body contains a Dictionary<String, T> whose value is an explicit-null nullable<T>, the generator was silently dropping those entries from the embedded JSON body via JSON.stringify of the IR's jsonExample (which leaves them as JS undefined). The expected struct built from the typed example shape retained them as Nullable<T>.null, so the decoded body and the expected struct disagreed at runtime equality.

Build the JSON body by walking the typed ExampleTypeReference shape directly so it stays in sync with the expected struct by construction.

Closes FER-10341

Co-Authored-By: barry.zou <barry.zou@buildwithfern.com>
@devin-ai-integration devin-ai-integration Bot requested a review from kafkas as a code owner May 4, 2026 22:16
@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

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-04-23T04:59:11Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
swift-sdk square 41s (n=5) 290s (n=5) 44s +3s (+7.3%)

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-23T04:59:11Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-05-04 22:23 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