@typeful-api/fastify
v0.1.1
Published
Fastify adapter for typeful-api
Maintainers
Readme
@typeful-api/fastify
Fastify adapter for typeful-api — build end-to-end type-safe OpenAPI-first APIs with Fastify. Compatible with Fastify 4.x+.
Installation
npm install @typeful-api/core @typeful-api/fastify fastify zodQuick Start
1. Define Your Contract
import { defineApi, route } from '@typeful-api/core';
import { z } from 'zod';
const api = defineApi({
v1: {
children: {
products: {
routes: {
list: route.get('/').returns(z.array(ProductSchema)).withSummary('List all products'),
create: route
.post('/')
.body(CreateProductSchema)
.returns(ProductSchema)
.withAuth('bearer')
.withSummary('Create a product'),
},
},
},
},
});2. Register the Plugin
import Fastify from 'fastify';
import { createFastifyPlugin, getLocals } from '@typeful-api/fastify';
const fastify = Fastify();
fastify.register(
createFastifyPlugin(api, {
v1: {
products: {
list: async ({ request }) => {
const { db } = getLocals<{ db: Database }>(request);
return await db.products.findMany();
},
create: async ({ request, body }) => {
const { db } = getLocals<{ db: Database }>(request);
return await db.products.create({ id: crypto.randomUUID(), ...body });
},
},
},
}),
{ prefix: '/api' },
);
fastify.listen({ port: 3000 });Hierarchical PreHandlers
Apply preHandler hooks at version, group, or route level:
fastify.register(
createFastifyPlugin(api, {
v1: {
preHandler: [corsPreHandler], // All v1 routes
products: {
preHandler: [dbPreHandler], // All product routes
list: handler,
create: handler,
},
},
}),
{ prefix: '/api' },
);Request Locals
Share state between preHandlers and route handlers:
import { createLocalsPreHandler, getLocals } from '@typeful-api/fastify';
const dbPreHandler = createLocalsPreHandler<{ db: Database }>((request) => ({
db: new Database(),
}));
// In your handler:
const handler = async ({ request }) => {
const { db } = getLocals<{ db: Database }>(request);
return await db.products.findMany();
};Handlers in Separate Files
Derive handler types from the contract:
import type { InferFastifyHandlers } from '@typeful-api/fastify';
import type { api } from './api';
type AppHandlers = InferFastifyHandlers<typeof api>;
export type ProductHandlers = AppHandlers['v1']['products'];import type { ProductHandlers } from '../types';
export const list: ProductHandlers['list'] = async ({ request }) => {
const { db } = getLocals<{ db: Database }>(request);
return await db.products.findMany();
};API
| Export | Description |
| ----------------------------------------- | -------------------------------------------------- |
| createFastifyPlugin(contract, handlers) | Create a typed Fastify plugin from an API contract |
| composePreHandlers(...hooks) | Compose multiple preHandler hooks |
| conditionalPreHandler(pred, hook) | Apply preHandler conditionally |
| createPreHandler(fn) | Create a typed preHandler hook |
| createLocalsPreHandler(fn) | Create a preHandler that populates request locals |
| decorateInstance(instance, key, value) | Type-safe Fastify instance decoration |
| getLocals(request) | Get typed locals from the request |
| setLocals(request, locals) | Set typed locals on the request |
| mergeLocals(request, locals) | Merge typed locals into the request |
Type Utilities
| Export | Description |
| --------------------------- | ---------------------------------------- |
| InferFastifyHandlers | Infer handler types from a contract |
| InferFastifyGroupHandlers | Infer handler types for a specific group |
| FastifyRouteContext | Typed context passed to handlers |
| RequestWithLocals | Fastify request with typed locals |
Documentation
For full documentation, examples, and guides, visit the typeful-api repository.
License
MIT
