Skip to content

fix(openapi): unmarshal HTTP responses from raw JSON text#389

Merged
jonaslagoni merged 3 commits into
mainfrom
fix/openapi-http-client-primitive-response
Jul 8, 2026
Merged

fix(openapi): unmarshal HTTP responses from raw JSON text#389
jonaslagoni merged 3 commits into
mainfrom
fix/openapi-http-client-primitive-response

Conversation

@ALagoni97

Copy link
Copy Markdown
Contributor

Why

When an OpenAPI operation's response schema is a primitive (e.g. type: string or type: number), the payload generator emits unmarshal(json: string) which JSON.parses its argument. But the generated HTTP client handed unmarshal the already-parsed value from response.json():

const rawData = await response.json();          // parsed value
const responseData = Module.unmarshal(rawData); // primitive unmarshal expects raw text

For primitive responses this both:

  • failed to type-checkRecord<any, any> is not assignable to string (TS2345), and
  • threw at runtimeJSON.parse on an already-parsed value (SyntaxError: Unexpected token 'h', "hello world" is not valid JSON).

Object/array payloads happened to work because their unmarshal accepts string | object / string | any[].

What

Hand unmarshal the raw JSON text via JSON.stringify(rawData):

const rawData = await response.json();
const responseData = Module.unmarshal(JSON.stringify(rawData));

Every unmarshal variant accepts a string — object (string | object), array (string | any[]), primitive (string), and unmarshalByStatusCode (any) — so this is uniform across all reply payload kinds. rawData stays the parsed object for the response wrapper's rawData field.

Tests

  • New openapi-primitive runtime fixture (test/runtime/openapi-primitive.json + codegen-openapi-primitive.mjs, wired into the runtime generate script) with operations returning a plain string and a plain number.
  • primitive-response.spec.ts drives the generated client against a server returning primitive bodies and asserts they unmarshal correctly. This fails before the fix (SyntaxError: ... is not valid JSON) and passes after.
  • channels.spec asserts the generated client unmarshals from JSON.stringify(rawData) (and never unmarshal(rawData)), locking in the generation change.
  • Full runtime HTTP suite: 16 suites / 128 tests pass; full unit suite: 50 suites / 630 tests pass.

Independent of #387 (auth narrowing) — both touch client.ts but in different regions.

🤖 Generated with Claude Code

Primitive-typed response payloads (e.g. `type: string`) generate
`unmarshal(json: string)` which JSON.parses its argument, but the HTTP
client handed unmarshal the already-parsed value from response.json().
That both failed to type-check (Record is not assignable to string) and
threw at runtime (JSON.parse on an already-parsed value) whenever an
operation response was a primitive.

Hand unmarshal the raw JSON text via JSON.stringify(rawData). Object and
array models already accept string or object, and unmarshalByStatusCode
takes any, so this is uniform across every reply payload kind, while
rawData stays the parsed object for the response wrapper.

Tests:
- New openapi-primitive runtime spec + config generating string/number
  response operations, plus a primitive-response runtime test proving they
  unmarshal correctly (fails before the fix with "not valid JSON").
- channels.spec asserts the generated client unmarshals from
  JSON.stringify(rawData).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ALagoni97 ALagoni97 requested a review from jonaslagoni as a code owner July 7, 2026 14:38
@netlify

netlify Bot commented Jul 7, 2026

Copy link
Copy Markdown

Deploy Preview for the-codegen-project canceled.

Name Link
🔨 Latest commit ba75d2c
🔍 Latest deploy log https://app.netlify.com/projects/the-codegen-project/deploys/6a4d0f545fa5110008102a8f

@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
the-codegen-project Ready Ready Preview, Comment Jul 8, 2026 9:33am
the-codegen-project-mcp Ready Ready Preview, Comment Jul 8, 2026 9:33am

@jonaslagoni

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.72.8 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants