Typed, provider-based framework for HTTP API access. Define your routes as Endpoint definitions, then call them through a composable provider stack — the same pattern the shelving/db module uses for databases.
Concepts
Endpoint
An Endpoint is a declarative, typed description of a single API route. It captures the HTTP method, the URL path (with optional {placeholder} segments), a shelving/schema for the request payload, and a schema for the response. Think of it the way Collection describes a database table — a shared definition both client and server reference.
import { GET, POST } from "shelving/api"
import { STRING, NUMBER } from "shelving/schema"
const getUser = GET("/users/{id}", { id: STRING }, { name: STRING, age: NUMBER })
const createPost = POST("/posts", { title: STRING, body: STRING }, { id: STRING })
For GET and HEAD requests, payload fields that don't fill a {placeholder} are appended as ?query params. All other methods send a JSON body.
Providers
An APIProvider is the abstract interface for executing calls against endpoints. ClientAPIProvider is the concrete implementation that uses the global fetch API. Wrap it with ThroughAPIProvider subclasses to layer in behaviour without rewriting transport logic:
APICache manages EndpointCache objects, one per endpoint. Each EndpointCache manages EndpointStore objects, one per unique payload — keyed by the rendered URL. For GET/HEAD requests, query params are part of the key so ?role=admin and ?role=editor are stored separately. EndpointStore fetches automatically on first read and de-duplicates in-flight requests.
The cache is primarily useful as the backbone of the React integration. Use it directly only when you need a reactive layer outside React.