Examples
Runnable mini projects live under examples/.
Thesis: the contract is law at every HTTP boundary. Handlers return
Result; wire shapes are schema-parsed; host failures are distinct from
domain failures; clients get an honest ClientErrorOf union; disclosure
defaults to fail-closed (public).
These examples mount serve. The same ContractDef also runs without HTTP —
createLocalClient / createDispatcher
on ./local.
Read them as five lessons:
- Shared contract —
packages/shared-contract:usersContractonly (domain statuses on each route).
Win: the contract is self-contained HTTP truth; host codes (validation_error/internal/route_not_found) are serve defaults;unavailableis client-only. - One framework mount — each stack imports that contract, writes handlers against the shared in-memory users database (
ResultAsync/railError), callsserve, then mounts.
Win: same law mounts anywhere;basePathandhandle()for shared pipelines; unmatched path ≠ resource missing; omitteddisclosure→public. - Gateway —
gateway: named contract exports,chain, graded disclosure,ClientErrorOf/unavailable.
Win: cross-service honesty without throw middleware. - Validators —
validators: same contract in Zod, Valibot, and ArkType.
Win: schemas are the wire law (input + always-on parsed output). - Files and streams —
files-and-streams: JSON onserve; multipart and SSE on sibling host handlers.
Win: the contract validates JSON shapes; the host owns the bytes. Guide: files and streams.
| Example | What it shows |
|---|---|
| Express | Node via @eddy-works/never-rest/node (toNodeHandler) |
| Hono | Fetch-native mount |
| Next App Router | handler.ts + catch-all /api/* with basePath: '/api' |
| SvelteKit | handler.ts + cooperative handle() in hooks.server.ts |
| Cloudflare Workers | Worker fetch handler |
| Gateway | chain, disclosure, ClientErrorOf |
| Validators | Zod / Valibot / ArkType (Standard Schema) |
| Files and streams | Sibling multipart + SSE; shadow RouteDef |
Yup is not supported: never-rest requires Standard Schema, which Yup does not implement.
See examples/README.md for ports and commands.
Express mount (same idea in every stack — contract in, handlers + serve local):
import { toNodeHandler } from '@eddy-works/never-rest/node';
import { serve, type Handlers } from '@eddy-works/never-rest/server';
import { usersContract } from '@never-rest-examples/shared-contract';
import { createUsersDb } from '@never-rest-examples/shared-contract/db';
const db = createUsersDb();
const usersHandlers: Handlers<typeof usersContract, undefined> = {
getUser: ({ params }) => db.getUser(params.id),
// …
};
const usersApi = serve(usersContract, usersHandlers, {
origin: 'express-demo',
});
const nodeHandler = toNodeHandler((request) => {
const context = undefined;
return usersApi(request, context);
});
app.use(nodeHandler);toNodeHandler is a thin IncomingMessage/ServerResponse bridge — not
Express middleware or an auth framework. Fetch-native runtimes call
serve() directly with a Web Request.