Mounting
Bind your router to the contract and serve it with an adapter.
The last step: server.api binds your router into the API object your framework adapter mounts. After this, your routes are live. The server handle comes from new KizunaServer(contract) (see Router).
server.api
import { server } from './server'; // new KizunaServer(contract) from @ts-kizuna/express, fastify, hono, or next
import { router } from './router';
import { requireUser, requireMember } from './guards';
export const api = server.api({
router,
guards: {
user: requireUser,
member: requireMember,
},
});Guards
If the contract declares identities, pass one guard per identity under guards. Created with server.guard, a guard verifies the extracted credential and returns the identity's context or a denial. The contract's auth map decides which routes each guard protects, so server.api attaches them automatically. See the Auth guide for the whole pipeline and the adapter pages for each framework's guard context.
Request context
For request-scoped values every handler needs (analytics ids, a logger, a tenant), declare them with Kizuna.requestContext, register them on new Kizuna(), and resolve each with server.requestContext. Resolvers run on every route, never deny, and handlers receive their values typed under each name.
Scheduled jobs
If the contract declares scheduled jobs, bind their handlers with server.jobs and pass them to server.api next to the router:
export const api = server.api({
router,
jobs: jobHandlers,
guards: {
scheduler: requireScheduler,
},
});api.mount then serves the two job endpoints, and every handler receives a typed jobs runner so a route can run one in process.
Plugins
If the contract declares plugins, pass their server implementations under plugins. A plugin is declared on the contract and implemented on the server, so the server half is imported separately:
import { mcpPluginServer } from '@ts-kizuna/mcp/server';
import { openApiPluginServer } from '@ts-kizuna/openapi/server';
export const api = server.api({
router,
plugins: {
mcp: mcpPluginServer(),
openApi: openApiPluginServer(),
},
});Whatever a plugin exports then arrives on every handler under plugins, keyed by name.
Middleware
For everything else (rate limiting, multipart parsing) use your framework's own middleware (app.use, Fastify hooks). Authentication belongs in guards, request-scoped values in requestContext.
Mounting
Once you have an api object, mount it with the adapter's mount verb:
Express:
import express from 'express';
import { api } from './server/api';
const app = express();
app.use(express.json());
api.mount(app);
app.listen(3000);Fastify:
import Fastify from 'fastify';
import { api } from './server/api';
const app = Fastify();
await api.mount(app);
app.listen({
port: 3000,
});Hono:
import { Hono } from 'hono';
import { api } from './server/api';
const app = new Hono();
api.mount(app);
export default app;Next.js:
import { api } from '../../../server/api';
export const { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS } = api.mount({
basePath: '/api',
});Reference
Next steps
For adapter-specific options (error handling, middleware, onError, etc.) see the adapter pages: