Skip to main content

Fastify Server

Installation​

pnpm add @ts-rest/fastify

Usage​

import Fastify from 'fastify';
import { initServer } from '@ts-rest/fastify';

const app = Fastify();

const s = initServer();

const router = s.router(contract, {
getPost: async ({ params: { id } }) => {
const post = await prisma.post.findUnique({ where: { id } });

return {
status: 200,
body: post,
};
},
createPost: async ({ body }) => {
const post = await prisma.post.create({
data: body,
});

return {
status: 201,
body: post,
};
},
});

app.register(s.plugin(router));

const start = async () => {
try {
await app.listen({ port: 3000 });
} catch (err) {
app.log.error(err);
process.exit(1);
}
};

start();

s.registerRouter is a function that takes a contract, a corresponding router with implementations for each route and a fastify app, and it will create the corresponding fastify routes for each endpoint with the correct method, paths and middleware and attach them to your fastify app.

Options​

You can pass an optional options object as the last argument for s.registerRouter.

type Options = {
logInitialization?: boolean; // print route initialization logs to console
jsonQuery?: boolean;
responseValidation?: boolean;
requestValidationErrorHandler?:
| 'combined'
| ((
err: TsRestRequestValidationError,
request: fastify.FastifyRequest,
reply: fastify.FastifyReply
) => void);
};

Response Validation​

To enable response parsing and validation, you can use the validateResponses option. If there is a corresponding response Zod schema defined in the contract for the returned status code, the response will be parsed and validated. If validation fails a ResponseValidationError will be thrown causing a 500 response to be returned.

s.registerRouter(contract, router, app, {
validateResponses: true,
});

Request Validation Error Handling​

The default functionality of handling request validation errors is combined which returns a 400 response with all validation errors in the body in this form.

{
pathParameterErrors: z.ZodError | null;
headerErrors: z.ZodError | null;
queryParameterErrors: z.ZodError | null;
bodyErrors: z.ZodError | null;
}

You can also pass a custom error handler function to the requestValidationErrorHandler option.

s.registerRouter(contract, router, app, {
requestValidationErrorHandler: (err, req, res, next) => {
// err is typed as ^ RequestValidationError
return res.status(400).json({
message: 'Validation failed',
});
},
});