fix(clients): build URL after request interceptors + thread finalError through error chain#3804
fix(clients): build URL after request interceptors + thread finalError through error chain#3804jnsdls wants to merge 4 commits intohey-api:mainfrom
Conversation
…r through error chain `client-next`: `beforeRequest()` computed the final URL before any request interceptor ran, so request interceptors that mutated `opts.baseUrl`, `opts.url`, `opts.path`, or `opts.query` had no effect — the pre-interceptor URL was already closed over by the fetch call. Move `buildUrl(opts)` to after the request interceptor loop in both the `request` and `makeSseFn` paths so interceptor mutations are honored. `client-next`, `client-ky`, `client-fetch`: error interceptor chains passed `error` (the raw initial error) into every interceptor invocation instead of `finalError` (the running accumulator). This broke composition: each interceptor saw the original error rather than the previous interceptor's output, so transformations from earlier interceptors were silently discarded. Thread `finalError` through instead, matching how `client-angular` and `client-ofetch` already work. Fixes hey-api#3803.
|
|
🦋 Changeset detectedLatest commit: 7f788f0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@jnsdls is attempting to deploy a commit to the Hey API Team on Vercel. A member of the Team first needs to authorize it. |
|
TL;DR — Fixes two bugs in the generated HTTP client templates: Key changes
Summary | 200 files | 4 commits | base: Deferred URL construction in
|
There was a problem hiding this comment.
Reviewed — no issues found.
Both fixes are correct and well-scoped. Moving buildUrl() after request interceptors in client-next ensures URL mutations from interceptors are honored, and threading finalError through the error chain aligns client-fetch, client-ky, and client-next with the already-correct behavior in client-angular and client-ofetch. All 183 snapshot changes are mechanical propagation of the three source template edits.
Task list (4/4 completed)
- Read changeset and PR description for context
- Review core client source changes (client-fetch, client-ky, client-next)
- Review snapshot changes for consistency
- Self-critique and submit review
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3804 +/- ##
==========================================
+ Coverage 39.80% 39.88% +0.08%
==========================================
Files 530 530
Lines 19467 19468 +1
Branches 5791 5791
==========================================
+ Hits 7748 7765 +17
+ Misses 9487 9478 -9
+ Partials 2232 2225 -7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Propagates the client template changes (URL built after request interceptors; finalError threaded through error interceptor chain) into the 10 example projects whose generated client.gen.ts files render one of the three affected client templates. This unblocks the examples:check CI job.
Adds regression tests that fail on pre-fix source and pass on post-fix source: - client-next: four tests asserting that request interceptor mutations to `opts.baseUrl`, `opts.url`, `opts.path`, and `opts.query` are reflected in the final fetch URL — previously the URL was built before interceptors ran, so these mutations were silently dropped. - client-next / client-fetch / client-ky: error-chain composition tests that install two error interceptors and assert the second sees the first's output (not the original error). Previously `finalError` was reassigned but the loop kept passing the untransformed `error` to each interceptor. client-fetch gets two variants (fetch-exception path and response-error path) since the bug existed in both interceptor loops.
@hey-api/codegen-core
@hey-api/json-schema-ref-parser
@hey-api/nuxt
@hey-api/openapi-ts
@hey-api/shared
@hey-api/spec-types
@hey-api/types
@hey-api/vite-plugin
commit: |
|
👋 Heads-up for reviewers: the error-interceptor fix in this PR is a subtle behavioral change for anyone who installed 2 or more error interceptors. Before this PR: each interceptor received the original error, and only the last interceptor's return value survived. A chain of N interceptors effectively behaved as if only the final one was installed. After this PR: each interceptor receives the previous interceptor's output (standard middleware composition — matches request/response interceptors, and matches how Gotcha to watch for: if an interceptor returns a falsy value (e.g. This caveat is now explicitly called out in both the changeset and the PR description. Flagging here so it's visible in the PR timeline before merge. |

Summary
Fixes #3803. Two closely-related bugs in the generated
client.gen.tstemplates:1.
client-nextbuilds the URL before request interceptors runbeforeRequest()inpackages/openapi-ts/src/plugins/@hey-api/client-next/bundle/client.tsreturned bothoptsand a pre-computedurl. Then:Any request interceptor that mutates
opts.baseUrl,opts.url,opts.path, oropts.query— the documented way to dynamically route requests (e.g. per-tenant base URLs, test env rewrites, migration shims) — had no effect. The pre-interceptor URL was already captured by the fetch call.Move
const url = buildUrl(opts)to AFTER the request interceptor loop. Same change applied tomakeSseFnso SSE paths are consistent.This bug is unique to
client-nextbecauseclient-fetchandclient-kyuseRequestobjects that interceptors mutate directly, so the URL picks up changes viarequest.url. Theclient-nextdesign runs interceptors onoptsdirectly, which makes post-interceptor URL recomputation mandatory.2. Error interceptor chain drops transformations (
client-next,client-ky,client-fetch)All three templates had:
Each interceptor saw the original
errorrather than the previous interceptor's output, so earlier interceptors' transformations were silently discarded — composition didn't work.client-angularandclient-ofetchalready threadfinalErrorcorrectly; this aligns the rest.Test plan
pnpm vitest run— all 2086 tests pass (3 pre-existing skips)pnpm lint— clean (oxfmt + eslint)pnpm typecheck— clean (35 tasks)client.gen.tssnapshots across@test/openapi-ts,@test/openapi-ts-nestjs-v11,@test/openapi-ts-orpc-v1,@test/openapi-ts-sdks,@test/openapi-ts-valibot-v1,@test/openapi-ts-zod-v3,@test/openapi-ts-zod-v4baseUrl/url/path/query) and error-chain composition inclient-next,client-fetch, andclient-kytest suites — revert the source fixes and these new tests fail@hey-api/openapi-ts: patch) with explicit behavioral-change noteNotes