Skip to content

feat(json-api-nestjs-sdk): let the Angular config carry an HttpContext - #128

Merged
klerick merged 2 commits into
masterfrom
fix/angular-http-adapter
Oct 10, 2026
Merged

klerick merged 2 commits into
masterfrom
fix/angular-http-adapter

Conversation

@klerick

@klerick klerick commented Oct 10, 2026

Copy link
Copy Markdown
Owner

A provider built inside a nested component gets its own SDK config while the
interceptors stay global, and nothing told them apart — every request looked the
same whichever provider made it. The config may now carry an HttpContext.

const SCOPE = new HttpContextToken<string>(() => 'root');

@Component({
  providers: [
    provideJsonApi(() => ({
      apiHost: '…',
      httpContext: new HttpContext().set(SCOPE, 'nested'),
    })),
  ],
})

A global interceptor then reads req.context.get(SCOPE) as usual.

Two commits

97f9ce0 — the translation, and a bug it was hiding. Angular's HttpClient
was injected as HttpInnerClient directly, with an as any papering over the
fact that the two disagree about argument positions:

HttpInnerClient HttpClient
get (url, { params }) (url, options)
post / patch (url, body) (url, body, options)
delete (url, body?) (url, options) — body goes inside

delete is the one that cost something: deleteRelationships handed
{ data: [...] } to the slot meant for headers, params and context, so the body
never reached the request. The fetch client reads that argument as a body, so it
only ever went wrong under Angular. post/patch were harmless but equally
misaligned — which is also why nothing could be attached to a request until now.

An adapter in the Angular file translates the four verbs, leaving the fetch and
axios adapters untouched.

e5f513d — the context. Attached to every verb, in whichever argument that
verb keeps its options in.

Shape

HttpContext stays out of JsonSdkConfig: the core keeps no Angular types, or
it would reach the fetch and axios builds where it means nothing. The Angular
file extends it as JsonSdkAngularConfig instead.

The config is now resolved once, behind an internal token. Three providers
read it, and a config factory called once per provider would have handed
JsonApiSdkService and AtomicFactory two different HttpContext objects —
the exact thing this feature exists to make comparable.

Tests

Written first, red before each commit. They assert the arguments the adapter
hands to HttpClient, verb by verb: that a delete body arrives as { body },
that post/patch keep the body in its own argument, that the context reaches
all four, that params and body survive alongside it, and that a config
without a context adds nothing.

The spec imports @angular/compiler first — loading @angular/common/http
outside an AOT build leaves its providers to be JIT-compiled, and without it the
import fails.

Verified green: unit across 9 projects, ts-test, e2e 137/137 on both MikroORM
and TypeORM. json-api-front:build:production fails on a CSS budget, as on
master.

🤖 Generated with Claude Code

klerick and others added 2 commits October 10, 2026 14:41
…lient in the Angular providers

Angular's HttpClient was injected as HttpInnerClient directly, with an `as any`
hiding that the two disagree about argument positions.

delete is the one that cost something: HttpInnerClient takes the body second,
HttpClient reads that position as options and expects the body inside them. So
deleteRelationships handed `{ data: [...] }` to a slot meant for headers,
params and context, and the body never reached the request. The fetch client
reads the same argument as a body, so this only ever went wrong under Angular.

post and patch were harmless but equally misaligned -- their options come third
for HttpClient, and HttpInnerClient has no slot for them at all, which is why
nothing could be attached to a request until now.

An adapter in the Angular file translates the four verbs. It sits where
HttpClient is already imported, so the fetch and axios adapters are untouched.

The spec imports @angular/compiler first: loading @angular/common/http outside
an AOT build leaves its providers to be JIT-compiled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A provider built inside a nested component gets its own SDK config while the
interceptors stay global, and until now nothing told them apart: every request
looked the same whichever provider made it.

The config may now carry an HttpContext, attached to every request the SDK
sends, which is the channel interceptors already read through
req.context.get(TOKEN).

HttpContext stays out of JsonSdkConfig -- the core keeps no Angular types, or
it would reach the fetch and axios builds where it means nothing. The Angular
file extends it instead, as JsonSdkAngularConfig.

The config is resolved once now, behind an internal token. Three providers read
it, and a config factory called once per provider would have handed
JsonApiSdkService and AtomicFactory two different HttpContext objects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nx-cloud

nx-cloud Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit e5f513d

Command Status Duration Result
nx affected --target=build --parallel=3 --exclu... ✅ Succeeded 1s View ↗
nx run json-api-server-e2e:e2e-micro --parallel=1 ✅ Succeeded 1m 15s View ↗
nx run json-api-server-e2e:e2e --parallel=1 ✅ Succeeded 1m 14s View ↗
nx run json-api-server:build:development ✅ Succeeded 1s View ↗
nx affected --target=ts-test --parallel=3 --pas... ✅ Succeeded <1s View ↗
nx affected --target=test --parallel=3 --passWi... ✅ Succeeded 1s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-10-10 12:51:05 UTC

@klerick
klerick merged commit 9a5f504 into master Oct 10, 2026
4 checks passed
@klerick
klerick deleted the fix/angular-http-adapter branch October 10, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant