npm install openapi-query openapi-fetch @tanstack/react-query
Generate TypeScript types from your OpenAPI schema using openapi-typescript:
npx openapi-typescript ./path/to/api.yaml -o ./src/api.d.ts
Create your client:
import createFetchClient from "openapi-fetch";
import createQueryClient from "openapi-query";
import type { paths } from "./api.d.ts";
const $fetch = createFetchClient<paths>({
baseUrl: "https://api.example.com",
});
const $query = createQueryClient($fetch);
Use queryOptions() to get a type-safe object ready for useQuery:
import { useQuery } from "@tanstack/react-query";
const { data, error } = useQuery(
$query.queryOptions("get", "/blogposts/{post_id}", {
params: { path: { post_id: "123" } },
}),
);
Both data and error are fully typed from your OpenAPI schema.
Use queryKey() for cache operations. Keys are structured as [method, path, options] and carry type information via TanStack Query's DataTag.
// Read cached data (typed!)
const cached = queryClient.getQueryData($query.queryKey("get", "/blogposts"));
// Invalidate queries
queryClient.invalidateQueries({
queryKey: $query.queryKey("get", "/blogposts"),
});
import { useInfiniteQuery } from "@tanstack/react-query";
const { data } = useInfiniteQuery({
...$query.infiniteQueryOptions("get", "/blogposts", {
params: { query: { tags: ["news"] } },
}),
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialPageParam: 0,
});
import { useMutation } from "@tanstack/react-query";
const { mutate } = useMutation($query.mutationOptions("put", "/tag/{name}"));
mutate({
params: { path: { name: "my-tag" } },
body: { description: "A new tag" },
});
| Method | Description |
|---|---|
queryOptions(method, path, init?) |
Returns { queryKey, queryFn } for useQuery |
queryKey(method, path, init?) |
Returns a typed query key for cache operations |
queryFn(method, path, init?) |
Returns a standalone query function |
infiniteQueryOptions(method, path, init?) |
Same as queryOptions but for infinite queries |
infiniteQueryKey(method, path, init?) |
Returns a query key marked for infinite queries |
mutationOptions(method, path) |
Returns { mutationFn } for useMutation |
mutationFn(method, path) |
Returns a standalone mutation function |
MIT