Typed Client
Generate the RouteMap
routegraph generate-clientWalks your loaded routes and writes AppRouteMap — a plain TypeScript type,
not a runtime artifact. No codegen step runs at request time; no .d.ts to
hand-maintain when a route changes.
routemap.ts (generated — don't hand-edit)
export interface AppRouteMap {
'/users': {
GET: { query: { role?: string }; response: User[] }
POST: { body: { name: string; email: string }; response: User }
}
'/users/:id': {
GET: { params: { id: string }; response: User }
DELETE: { params: { id: string }; response: { ok: true } }
}
}createClient
import { createClient } from '@routegraph/client'
import type { AppRouteMap } from './routemap.js'
const api = createClient<AppRouteMap>({
baseUrl: 'http://localhost:3000/api',
headers: { Authorization: `Bearer ${token}` },
timeout: 5000,
})| Option | Type | Description |
|---|---|---|
baseUrl | string | required |
headers | Record<string,string> | () => Record<string,string> | sent on every request |
fetch | typeof fetch | inject your own — great for testing |
onError | (err: ClientError) => void | called before the error is thrown |
timeout | number (ms) | aborts the request automatically |
Making requests
const users = await api['/users'].GET({ query: { role: 'admin' } })
console.log(users.data) // typed from the route's response schema
await api['/users'].POST({ body: { name: 'Ada' } })
// ^^^^^^^^^^^^^^^ TS error
// the route's body schema also requires `email`Wrong params, missing body fields, and mistyped query keys are all compile errors — before you ever hit send.
ClientResponse / ClientError
interface ClientResponse<T> {
data: T
status: number
headers: Headers
}
class ClientError extends Error {
status: number
issues?: ValidationIssue[] // present on 400s from RouteGraph's own validation
}⚠️
The client’s type safety is compile-time only. There is no runtime
response validation on the client side — data is typed as T, not
re-parsed through Zod on the way in. If a server response doesn’t
actually match its schema, the client will not catch that at runtime.
Cancellation
const controller = new AbortController()
api['/users'].GET({ signal: controller.signal })
controller.abort()Testing with an injected fetch
const api = createClient<AppRouteMap>({
baseUrl: 'http://localhost:3000/api',
fetch: mockFetch, // any function matching the global fetch signature
})