Generating Calls from ts-rest
Use Callsheet with ts-rest contracts, with or without code generation.
If you already have a ts-rest contract, you can generate Callsheet directly from it. Callsheet reads the contract and builds a shared call module your app can use anywhere.
Start from a contract
This guide assumes you already have a ts-rest contract. If you don't, ts-rest's own docs are the best place to get set up.
Here is a small contract with one query and one mutation:
import { initContract } from '@ts-rest/core';
const c = initContract();
export const contract = c.router({
films: {
byId: c.query({
method: 'GET',
path: '/films/:id',
pathParams: c.type<{ id: string }>(),
responses: {
200: c.type<{ film: { id: string; title: string } }>(),
},
}),
update: c.mutation({
method: 'PATCH',
path: '/films/:id',
pathParams: c.type<{ id: string }>(),
body: c.type<{ title: string }>(),
responses: {
200: c.type<{ updated: true }>(),
},
}),
},
});Point Callsheet at the contract
If you haven't already, install the packages you need for the generated ts-rest workflow:
pnpm add @callsheet/react-query @ts-rest/core
pnpm add -D @callsheet/codegen@callsheet/codegen ```
</Tab>
<Tab value="yarn">
```sh
yarn add @callsheet/react-query @ts-rest/core
yarn add @callsheet/codegen -DThen create a callsheet.config.ts at your project root:
import { defineConfig } from '@callsheet/codegen';
export default defineConfig({
sources: {
tsRest: [
{
importFrom: './src/rest/contract',
exportName: 'contract',
pathPrefix: ['rest'],
},
],
},
output: {
file: './src/generated/calls.ts',
},
});The tsRest source block tells Callsheet where to find your contract and how to read it:
importFromis the path to the module that exports the contract.exportNameis the name of the contract export in that module.pathPrefixis optional. It namespaces the generated calls under a prefix which is useful when your Callsheet also includes calls from other sources like GraphQL. In this example, the generated paths will start withrest.films.*instead of justfilms.*.
Generate your calls
Run codegen to build the call module:
pnpm callsheet-codegen --config callsheet.config.tssh npx callsheet-codegen --config callsheet.config.ts
yarn callsheet-codegen --config callsheet.config.tsCallsheet reads the contract, finds each route, and infers whether it should be a query or mutation based on the route definition in your contract. The generated module looks like this:
import { defineCalls, mutation, query } from '@callsheet/react-query';
import { contract } from '../rest/contract';
export const calls = defineCalls({
rest: {
films: {
byId: query(contract.films.byId),
update: mutation(contract.films.update),
},
},
});Each route in the contract becomes a call in the generated module. The contract is still the typed source, and the generated calls module is the shared surface your app imports from.
Use generated calls in React Query
Once generated, use the calls through the React Query APIs you already know:
import { queryOptions } from '@callsheet/react-query';
import { calls } from './generated/calls';
const film = useQuery(
queryOptions(calls.rest.films.byId, {
input: { params: { id: 'wall-e' } },
select: (data) => data.film,
}),
);
const updateFilm = useMutation(calls.rest.films.update);This is the same shared call surface used throughout the rest of the Callsheet docs. The only difference here is the typed source the calls were built from. To add shared defaults or invalidation rules, read Using Callsheet with React Query.
Without code generation
If you don't want to use codegen, you can define ts-rest calls manually using @callsheet/ts-rest. In that setup, add @callsheet/ts-rest and wrap the routes yourself:
pnpm add @callsheet/ts-restsh npm add @callsheet/ts-rest yarn add @callsheet/ts-restimport { defineCalls } from '@callsheet/react-query';
import { query, mutation } from '@callsheet/ts-rest';
import { contract } from './rest/contract';
export const calls = defineCalls({
films: {
byId: query(contract.films.byId),
update: mutation(contract.films.update),
},
});The result is the same shared call surface.
Related Docs
- Codegen Config for the full config reference
- Manual Setup if you want to compare the broader manual path
- Using Callsheet with React Query for shared defaults, overrides, and invalidation