Without a Backend (Gradual Migration)
The ideal way to use ts-rest
is to control both the client and server, however, we don't live in a perfect world where we can afford to rewrite everything at once! This guide will show you how to use ts-rest
without a backend, commonly utilised to help migrate an existing application to ts-rest
.
Adding @ts-rest
to your project
- pnpm
- npm
- yarn
pnpm add @ts-rest/core @ts-rest/react-query
npm install @ts-rest/core @ts-rest/react-query
yarn add @ts-rest/core @ts-rest/react-query
This command installs the core, and the react-query
adapter. We strongly recommend using react-query
as it is a fantastic way to handle many common problems with data fetching in react, and ts-rest provides first class support for it.
Initialise a Contract
The first step is to create a contract, normally in the ts-rest docs we advise you to create this in a shared library, either in a monorepo or published to a package registry. However, for this guide we're going to create it in the same project as the client.
const c = initContract();
export const contract = c.router({
getPosts: {
method: 'GET',
path: '/posts',
responses: {
200: c.type<{ posts: Post[]; total: number }>(),
},
query: z.object({
take: z.string().transform(Number).optional(),
skip: z.string().transform(Number).optional(),
search: z.string().optional(),
}),
summary: 'Get all posts',
},
// ...
});
Read our core guide to learn more about contracts.
Setup react-query in your project
It's worth following the excellent @tanstack/react-query
installation guide to get started with react-query
. We're going to assume you've already done this (snippet below)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Create a client
const queryClient = new QueryClient();
const App = () => {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
);
};
Consume the Contract
Now that we have a contract, we can use it to create a client. We're going to use react-query
to handle the data fetching, but you can use any data fetching library you want.
import { contract } from './contract';
export const client = initQueryClient(contract, {
baseUrl: 'http://localhost:3333',
baseHeaders: {},
});
const YourComponent = () => {
const queryResult = client.getPosts.useQuery(
['posts'], // <- queryKey
{ query: { take: 10 } }, // <- Query params, Params, Body etc (all typed)
{ staleTime: 1000 } // <- react-query options (optional)
);
// ... use the query result
};
You should probably put the client somewhere accessible to all components, possibly at the top level of your application.
Next Steps
Now that you're using ts-rest in a non-breaking way you're in an excellent position to experiment with your team, if the experiment is successful you can start to migrate your backend to use ts-rest, all incrementally and without breaking your application!