Skip to content

feat: typed HttpError + input-driven error handling#429

Merged
jonaslagoni merged 10 commits into
mainfrom
finalize_http_error_codes
Jul 23, 2026
Merged

feat: typed HttpError + input-driven error handling#429
jonaslagoni merged 10 commits into
mainfrom
finalize_http_error_codes

Conversation

@jonaslagoni

Copy link
Copy Markdown
Contributor

What

Replaces the static, hardcoded handleHttpError in the generated HTTP client with an input-driven, typed error contract:

  • A generated HttpError extends Error class carrying { status, statusText, body? } is now exported from every http_client.ts.
  • handleHttpError(status, statusText, body?) throws HttpError (not a plain Error), and its switch cases are generated from the error status codes the input document actually declares.
  • The per-operation fetch code parses the error response body and forwards it into the thrown HttpError.

For OpenAPI inputs, error status codes (>= 400 plus default) are aggregated document-wide, each becoming an explicit case with the standard HTTP reason phrase as its message (e.g. 400 → 'Bad Request', 404 → 'Not Found'). For AsyncAPI inputs (which declare no error responses) the handler is default-only. Any undeclared code falls through to a generic HTTP Error: <status> <statusText> default.

Why

The old handleHttpError was emitted byte-for-byte every run with fixed cases (401/403/404/500) regardless of the input document, and threw a plain Error. Consumers had:

  • no typed error to catch (instanceof),
  • no structured access to .status / .statusText,
  • no access to the parsed error body,
  • error messages hardcoded in the generator rather than derived from the API contract.

This makes generated HTTP clients' error handling reflect the actual API spec and gives consumers a first-class, inspectable error type.

Changes

Generator (src/codegen/)

  • channels/protocols/http/common-types.ts — add the exported HttpError class; add a generator-side HTTP_REASON_PHRASES map and a renderHandleHttpErrorBody helper; change renderHttpCommonTypes to the object-parameter form { securitySchemes, errorStatusCodes }; emit an input-driven handleHttpError(status, statusText, body?).
  • channels/openapi.ts — add collectErrorStatusCodes / collectResponseErrorCodes to gather declared error codes (>= 400 + default) document-wide and thread them into renderHttpCommonTypes.
  • channels/protocols/http/client.ts — the per-operation error branch now reads the body defensively (await response.json().catch(() => undefined)) and forwards it to handleHttpError.

Tests

  • Rewrote HTTP runtime specs (methods, retry, openapi) to assert the typed contract (instanceof HttpError, .status, .statusText, .body, message form).
  • Aligned OAuth2 / hooks / api-auth runtime specs to the new default-form messages (kept 'Unauthorized' where the OAuth2 refresh branch throws its own error before handleHttpError).
  • Added focused unit assertions (OpenAPI cases 400/404/405 + reason phrases; AsyncAPI default-only) and refreshed the channel snapshots.

Example & docs

  • Regenerated examples/openapi-http-client with the typed HttpError and added an instanceof HttpError demo. (Regeneration also picked up pre-existing drift: Modelina next.14 payload changes and a server → baseUrl context-field rename; the hand-written demo and README were updated to match.)
  • Added an "Error Handling" section to docs/protocols/http_client.md.

Testing

  • npm run build — passes.
  • npm run lint — passes (0 warnings, incl. typecheck:test).
  • npm test — 53 suites, 675 passed / 1 skipped, 78 snapshots.
  • HTTP runtime suite — cd test/runtime/typescript && npm run test:http — 15 suites, 114 passed.
  • npm run generate:assets produces no schemas/ diff (no Zod config changed), confirming schemas don't need regeneration.
  • Blackbox — no http_client config exists in test/blackbox/, so not applicable (behavior is covered by unit + runtime).

Per repo memory, the npm ci-gated prepare:pr step can fail on pre-existing runtime lockfile drift; the individual quality-gate steps above were run and validated directly instead.

Notes

⚠️ BREAKING CHANGE — major version bump. Generated http_client.ts changes shape:

  • adds an exported HttpError class;
  • handleHttpError now takes (status, statusText, body?) and throws HttpError instead of Error;
  • error switch cases are input-derived (OpenAPI) or default-only (AsyncAPI);
  • every operation's error branch parses and forwards the error body.

Consumers catching Error still catch HttpError (it's a subclass). Code asserting exact error messages on AsyncAPI-generated clients will now see the HTTP Error: <status> <statusText> default form (previously 'Not Found' / 'Forbidden' / 'Internal Server Error') unless those codes are declared in the input. The title omits !; if semantic-release needs it, this note documents the breaking nature — add a BREAKING CHANGE: commit footer on squash-merge if a major bump is required.

Unchanged: the success-path unmarshalByStatusCode mechanism, RetryConfig / retryableStatusCodes, the onError hook signature, and the OAuth2 401-refresh branch. No new Zod config / opt-in flag. No other protocols or generators touched.

jonaslagoni and others added 8 commits July 23, 2026 16:52
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orm messages

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jonaslagoni
jonaslagoni requested a review from ALagoni97 as a code owner July 23, 2026 15:37
@vercel

vercel Bot commented Jul 23, 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 23, 2026 4:10pm
the-codegen-project-mcp Ready Ready Preview, Comment Jul 23, 2026 4:10pm

@jonaslagoni jonaslagoni changed the title feat(http): typed HttpError + input-driven error handling feat: typed HttpError + input-driven error handling Jul 23, 2026
@jonaslagoni
jonaslagoni merged commit 084228f into main Jul 23, 2026
16 checks passed
@jonaslagoni
jonaslagoni deleted the finalize_http_error_codes branch July 23, 2026 16:13
@jonaslagoni

Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 0.79.0 🎉

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