@web-ts-toolkit/access-router-client
Typed Axios-based client utilities for @web-ts-toolkit/access-router model routers, data routers, and root batch routes.
This package is designed to mirror the request contract exposed by @web-ts-toolkit/access-router:
- model routers become
ModelService<T>instances - data routers become
DataService<T>instances - root-router batching becomes
adapter.group(...) - model responses become mutable
Model<T>wrappers withsave(),reset(), and dirty tracking
Relationship To The Server
access-router-client is not a generic REST SDK generator.
It assumes the server follows the conventions from @web-ts-toolkit/access-router, including:
- model routes mounted at a known
basePath - data routes mounted at a known
basePath - advanced query routes mounted under a query segment such as
__query - advanced mutation routes mounted under a mutation segment such as
__mutation - optional root batching mounted under a root route such as
/api/root
If the server uses custom route segments, configure the client to match them exactly.
Installation
- npm
- Yarn
- pnpm
- Bun
npm install @web-ts-toolkit/access-router-client
yarn add @web-ts-toolkit/access-router-client
pnpm add @web-ts-toolkit/access-router-client
bun add @web-ts-toolkit/access-router-client
pnpm add @web-ts-toolkit/access-router-client
What It Exposes
Main entrypoint:
createAdapter(...)ModelServiceDataServiceModel- response and query helper types from
./types
Quick Start
import { createAdapter } from '@web-ts-toolkit/access-router-client';
interface User {
_id?: string;
name: string;
role: string;
public: boolean;
}
const adapter = createAdapter({
baseURL: 'http://localhost:3000/api',
});
const userService = adapter.createModelService<User>({
modelName: 'User',
basePath: 'users',
});
const listResponse = await userService.listAdvanced(
{ role: 'admin' },
{ select: ['name', 'role'], limit: 10 },
{ includeCount: true },
);
const user = await userService.read('user-id-1');
user.data.role = 'owner';
await user.data.save();
const grouped = await adapter.group(
userService.readAdvanced('user-id-1', { select: ['name'] }),
userService.countAdvanced({ role: 'admin' }),
);
Typical Workflow
In practice, a common client flow looks like this:
- create one adapter per API origin
- create one service per router you care about
- read documents into
Model<T>wrappers - mutate the wrapper locally
- persist with
save()or call explicit service methods - use
group(...)when severalaccess-routerrequests should share one round trip
Core Concepts
Lazy requests
Service methods return promise-like lazy requests.
- the request does not execute until you
await,.then(),.catch(),.finally(), or call.exec() - lazy requests carry internal metadata that
adapter.group(...)uses to build a root batch request - grouped requests must come from this client package, not from raw Axios calls
Response shape
Most service methods resolve to a normalized shape:
interface Response<TRaw, TData = TRaw> {
success: boolean;
raw: TRaw;
data: TData;
message: string;
status: number;
headers: Record<string, string>;
}
Common conventions:
success === truemeans the HTTP request completed and the router operation succeededrawholds the original payload after client-side normalizationdataholds higher-level client objects such asModel<T>wrappers for model readsmessageis populated for errors and is extracted from structured problem payloads when possible
For list-style responses:
totalCountis present on list response types- when the server returns count metadata, the client normalizes it into that field
- when count metadata is not requested,
totalCountmay be0or a fallback based on the route shape
Model<T> wrappers
Model reads and writes return Model<T> instances instead of plain objects.
That wrapper provides:
- direct property access like
user.data.name assign(...),get(...), andset(...)isDirty(...)andmarkModified(...)save()for create-or-update persistencereset()to restore the last loaded or persisted snapshottoObject()/toJSON()for safe cloning and serialization
Package Guide
- Adapter And Setup: configuring
createAdapter(...), batching, wrapping arbitrary endpoints, and cache behavior - Services:
ModelServiceandDataServicemethods, defaults, subqueries, and subdocuments - Model: dirty tracking, save/reset behavior, path-based updates, and collision handling
- TypeScript And Errors: typed selects, response typing, and
ServiceError
Routing Notes
- model and data service requests use the router paths you configure in
basePath - grouped
adapter.group(...)requests target the root router path, which defaults toroot - if your root router uses another path, pass
rootRouterPathas the secondcreateAdapter(...)argument - custom query or mutation route segments must match the server-side
queryRouteSegmentand mutation route configuration
Common path mapping
Typical server/client alignment looks like this:
// server
runtime.createRouter('User', {
basePath: '/api/users',
queryRouteSegment: '__query',
});
// client
const adapter = createAdapter({ baseURL: 'http://localhost:3000/api' });
const userService = adapter.createModelService({
modelName: 'User',
basePath: 'users',
queryPath: '__query',
});
The client basePath is relative to the adapter baseURL, not the full server path.
When To Use It
Use access-router-client when you want:
- a typed client over
access-routermodel or data routes - model instances that can be mutated locally and persisted with
save() - root batched requests through
adapter.group(...) - a consistent error contract without hand-writing Axios wrappers
If you only need HTTP requests and do not use access-router, plain Axios is usually simpler.