React Query gives you great building blocks but it's up to you to decide how operations should be organized.
Callsheet provides one shared place for your operations, defaults, and related behaviors, built on the APIs you already use.
pnpm add @callsheet/react-query @tanstack/react-querynpm install @callsheet/react-query @tanstack/react-queryCallsheet builds from typed operations. It can also generate calls from your existing GraphQL and typed REST sources.
- Use
@callsheet/react-queryto define calls. - Add
@callsheet/codegento auto-generate calls from GraphQL Code Generator output. - Add
@callsheet/ts-restfor ts-rest support.
Callsheet is easiest to see in code. Here is the same workflow in React Query with and without Callsheet:
Without Callsheet:
export const filmKeys = {
list: () => ['films', 'list'],
detail: (id: string) => ['films', 'detail', id],
};
export const featuredFilmsOptions = queryOptions({
queryKey: filmKeys.list(),
queryFn: () => filmApi.featured(),
});
export const filmByIdOptions = (id: string) =>
queryOptions({
queryKey: filmKeys.detail(id),
queryFn: () => filmApi.byId({ id }),
staleTime: 30_000,
});
export function useUpdateFilm() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (input: { id: string; title: string }) => filmApi.update(input),
onSuccess: (_, variables) => {
queryClient.invalidateQueries({ queryKey: filmKeys.list() });
queryClient.invalidateQueries({
queryKey: filmKeys.detail(variables.id),
});
},
});
}With Callsheet:
filmCalls.ts
export const calls = defineCalls({
films: {
featured: query({
family: ['films', 'list'],
}),
byId: query<{ id: string }>({
family: ['films', 'detail'],
staleTime: 30_000,
}),
update: mutation<{ id: string; title: string }>({
invalidates: [
['films', 'list'],
['films', 'detail'],
],
}),
},
});FilmPage.tsx
const featuredFilms = useQuery(queryOptions(calls.films.featured));
const film = useQuery(queryOptions(calls.films.byId, { input: { id } }));
const updateFilm = useMutation(calls.films.update);Components still use normal React Query APIs, but they now build on a shared call definition with conventions organized in one place.
Callsheet works with any typed source: GraphQL documents, REST contracts, or calls you define by hand. The result is the same shared structure.
- React Query: TanStack Query
- GraphQL generation: GraphQL Code Generator
- Typed REST generation: ts-rest
- Manual integration for custom typed operations
- Infinite query support for the React Query adapter
- Additional adapters, starting with
swr,urql, and Apollo
See the full roadmap: Roadmap
MIT