Skip to content

docs(skills): add /api-client — typed client recipe for response routes - #540

Merged
ivogt merged 1 commit into
mainfrom
docs/typed-client-skill
Jun 7, 2026
Merged

ivogt merged 1 commit into
mainfrom
docs/typed-client-skill

Conversation

@ivogt

@ivogt ivogt commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a new skill, /api-client, that teaches consumers how to consume their own path.json() response-route APIs from first-party TypeScript with a typed client — and ships a ~50-line copy-paste helper that does it.

Follow-up to #539 (bare-T + RFC 9457 problem+json). It's a recipe, not a new framework export: the helper composes existing public exports (RouteResponse, ExtractParams, createReverse). Docs-only — no runtime or public-API change.

Why

Today, consuming your own API with types means hand-rolling a client per app (the test-app's api-shop-client.ts is ~105 lines of it), and the default consumer who skips that gets fetch(url).then(r => r.json()) → any. The recipe collapses that to:

const api = createApiClient(apiShopPatterns, routes, { baseUrl });
await api.health.get();                            // no params → callable bare
await api.product.get({ params: { productId } });  // params typed + required
//    ^ result is the bare payload (RouteResponse), not `any`, no `.data`
  • Output typed from the handler's return (RouteResponse), no codegen.
  • Path params required + typed from the route pattern; missing/misspelled param = compile error.
  • Errors throw a typed ApiError carrying the ProblemDetails body.

Scope call-out (deliberate)

The typed client is a first-party TypeScript convenience — it needs your route types. External/third-party consumers use the plain wire directly (bare JSON + application/problem+json), which needs no client. Language-agnostic OpenAPI generation is intentionally deferred as the separate third-party lever. The skill states this explicitly so nobody mistakes the recipe for a third-party SDK.

Verification

The helper was compile-verified against the e2e/test-app api-shop routes (temporary type-test, since removed): required-param enforcement, no-arg paramless routes, typed .post({ body }), and @ts-expect-error on unknown routes / wrong param names. typecheck, lint, format all green.

Surface

  • skills/api-client/SKILL.md (new)
  • skills/rango/SKILL.md — indexed in the skill table
  • skills/response-routes/SKILL.md — cross-linked ("Consuming response routes")

@pkg-pr-new

pkg-pr-new Bot commented Jun 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@rangojs/router@540

commit: 25ffd10

@ivogt
ivogt force-pushed the docs/typed-client-skill branch from 25ffd10 to fe7bdee Compare June 7, 2026 16:13
…es [skip ci]

A copy-paste recipe (not a new framework export) for consuming your own
path.json() APIs from first-party TypeScript: route params typed + required
from the pattern (optional-only params still passable), response payloads
typed via RouteResponse (no codegen, no `.data`), typed ProblemDetails errors.

Client-safe by construction: only type-only imports from @rangojs/router plus
an in-helper path builder — no createReverse (a server/RSC-only export that
throws in the browser). Accepts both string and { path } route-map entries.
`body` is `unknown` (serialized JSON); typed request input is out of scope.

Compile-verified against api-shop + search routes and the full param-arity
matrix (no-param, required, optional-only, mixed). Indexed in /rango;
cross-linked from /response-routes. Docs-only; no runtime change.
@ivogt
ivogt force-pushed the docs/typed-client-skill branch from fe7bdee to 76c0ae4 Compare June 7, 2026 17:22
@ivogt
ivogt merged commit ca1cfef into main Jun 7, 2026
@ivogt
ivogt deleted the docs/typed-client-skill branch June 7, 2026 17:51
ivogt added a commit that referenced this pull request Jun 9, 2026
Bring in main (#540-#551: dev/prod matching stability + lazy-include fixes, perf
benchmarks, docs reorg/archive, release 0.0.0-experimental.116). Resolve the two
internal docs-map conflicts (feature-file-map.md, feature-map.md) by keeping main's
cell updates AND the branch's testing rows (the "Consumer testing primitives" row
and the six ./testing* export-surface rows).

Gate: typecheck 12/12, test:unit:all EXIT=0 (router 3537 + 6 todo, cloudflare-basic
39, RSC 27), lint 0/0, format.
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