Skip to main content

Next.js Server

Installation​

pnpm add @ts-rest/next

Usage​

For maximum type safety, by default @ts-rest/next uses a single endpoint for all routes.

info

It is possible to split out to multiple endpoints by having multiple [...ts-rest].tsx files in different folders, so long as the routers you use all begin with the same path e.g. all /posts endpoints in a posts folder.

// pages/api/[...ts-rest].tsx
import { createNextRoute, createNextRouter } from '@ts-rest/next';

const postsRouter = createNextRoute(api.posts, {
createPost: async (args) => {
const newPost = await posts.createPost(args.body);

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

const router = createNextRoute(api, {
posts: postsRouter,
});

// Actually initiate the collective endpoints
export default createNextRouter(api, router);

createNextRouter is a function that takes a router and a complete router, and creates endpoints, with the correct methods, paths and callbacks.

JSON Query Parameters​

To handle JSON query parameters, you can use the jsonQuery option.

export default createNextRouter(api, router, { jsonQuery: true });

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.

export default createNextRouter(api, router, { validateResponses: true });

Error Handling​

You can create a global error handler to handle any thrown errors by using the errorHandler option. This includes response validation errors.

export default createNextRouter(api, router, {
responseValidation: true,
errorHandler: (error: unknown, req: NextApiRequest, res: NextApiResponse) => {
if (error instanceof ResponseValidationError) {
console.log(error.cause);
return res.status(500).json({ message: 'Internal Server Error' });
}
},
});

Future Work​

As this pattern doesn't support a lambda per endpoint, it is planned to provide a helper utility to allow individual endpoints to be created.

The downside of this is that it will not be possible to give a Typescript warning if the path is incorrect.