ts-rest
RPC-like client and server helpers for a magical end to end typed experience
Introduction
ts-rest offers a simple way to define a contract for your API, which can be both consumed and implemented by your application, giving you end to end type safety without the hassle or code generation.
Features
- End to end type safety ๐
- RPC-like client side interface ๐ก
- Tiny bundle size ๐ (1kb!)
- Well-tested and production ready โ
- No Code Generation ๐โโ๏ธ
- Zod support for runtime type checks ๐ฎโโ๏ธ
- Full optional OpenAPI integration ๐
Super Simple Example
Easily define your API contract somewhere shared
const contract = c.contract({
getPosts: {
method: 'GET',
path: '/posts',
query: z.object({
skip: z.number(),
take: z.number(),
}),
responses: {
200: c.type<Post[]>(),
},
headers: z.object({
'x-pagination-page': z.coerce.number().optional(),
}),
},
});
Fulfil the contract on your sever, with a type-safe router:
const router = s.router(contract, {
getPost: async ({ params: { id } }) => {
return {
status: 200,
body: prisma.post.findUnique({ where: { id } }),
};
},
});
Consume the api on the client with a RPC-like interface:
const result = await client.getPosts({
headers: { 'x-pagination-page': 1 },
query: { skip: 0, take: 10 },
});
Quickstart
Install the core package
yarn add @ts-rest/core
yarn add @ts-rest/react-query
yarn add @ts-rest/nest @ts-rest/express
yarn add @ts-rest/open-api
Create a contract, implement it on your server then consume it in your client. Incrementally adopt, trial it with your team, then get shipping faster.
Star History
Contributors โจ
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!