Skip to main content

Middleware

You can add middleware to your routes through ts-rest directly instead of having to attach them to your app directly. They are regular Express.js request handlers, but with the added benefit of having a typed contract route attached to the Request object at req.tsRestRoute.

This allows you to pass metadata from your contract to your middleware to be used for authorization, logging, etc.

Route Middleware

In the below example we show how you can add middleware that only runs for a specific route.

import { initServer } from '@ts-rest/express';
import { contract } from './contract';

const s = initServer();

const router = s.router(contract, {
getPost: {
middleware: [
(req, res, next) => {
// req.tsRestRoute is typed as the contract route
console.log('Called: ', req.tsRestRoute.method, req.tsRestRoute.path);
// prints: Called: GET /posts/:id
next();
}
],
handler: async ({ params: { id } }) => {
const post = prisma.post.findUnique({ where: { id } });

return {
status: 200,
body: post ?? null,
};
}
},
});

createExpressEndpoints(contract, router, app);

Global Middleware

You can also add middleware that runs for all routes in a contract. These run before any route-specific middleware.

import { initServer } from '@ts-rest/express';
import { contract } from './contract';

const s = initServer();

const router = s.router(contract, {
getPost: {
middleware: [
(req, res, next) => {
// req.tsRestRoute is typed as the contract route
console.log('Called: ', req.tsRestRoute.method, req.tsRestRoute.path);
// 'GET' ^ '/posts/:id' ^
next();
}
],
handler: async ({ params: { id } }) => {
const post = prisma.post.findUnique({ where: { id } });

return {
status: 200,
body: post ?? null,
};
}
},
});

createExpressEndpoints(contract, router, app, {
globalMiddleware: [passport.authenticate('jwt', { session: false })]
});