Introduction
openapi-typesafe-react-query is a type-safe tiny wrapper (about 1 kB minified) around @tanstack/react-query to work with OpenAPI schema.
It works by using openapi-typesafe-fetch and openapi-typesafe so you get all the following features:
- No typos in URLs or params.
- All parameters, request bodies, and responses are type-checked against your schema
- No manual typing of your API
- Eliminates
anytypes that hide bugs - Also eliminates
astype overrides that can also hide bugs
import createFetchClient from "openapi-typesafe-fetch";
import createClient from "openapi-typesafe-react-query";
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typesafe
const fetchClient = createFetchClient<paths>({
baseUrl: "https://myapi.dev/v1/",
});
const $api = createClient(fetchClient);
const MyComponent = () => {
const { data, error, isLoading } = $api.useQuery(
"get",
"/blogposts/{post_id}",
{
params: {
path: { post_id: "5" },
},
},
);
if (error) return `An error occurred: ${error.message}`;
if (isLoading || !data) return "Loading...";
return <div>{data.title}</div>;
};Setup
Install this library along with openapi-typesafe-fetch and openapi-typesafe:
npm i openapi-typesafe-react-query openapi-typesafe-fetch @tanstack/react-query
npm i -D openapi-typesafe typescriptThe hooks call TanStack Query's own hooks, which read a QueryClient from a QueryClientProvider. createClient gives you the typed hooks ($api), not a QueryClient, so you need both: create the QueryClient once and wrap your app in its provider.
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
export function App() {
return (
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
);
}Without a provider every hook throws No QueryClient set, use QueryClientProvider to set one; you can also pass a QueryClient as the last argument of each hook. If you get that error with a provider in place, two copies of @tanstack/react-query are installed (npm ls @tanstack/react-query): it is a peer dependency, so the app and this package must share one.
Highly recommended
Enable noUncheckedIndexedAccess in your tsconfig.json (docs)
Next, generate TypeScript types from your OpenAPI schema using openapi-typesafe:
npx openapi-typesafe ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.tsBasic usage
Once your types have been generated from your schema, you can create a fetch client, a react-query client and start querying your API.
import createFetchClient from "openapi-typesafe-fetch";
import createClient from "openapi-typesafe-react-query";
import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typesafe
const fetchClient = createFetchClient<paths>({
baseUrl: "https://myapi.dev/v1/",
});
const $api = createClient(fetchClient);
const MyComponent = () => {
const { data, error, isLoading } = $api.useQuery(
"get",
"/blogposts/{post_id}",
{
params: {
path: { post_id: "5" },
},
},
);
if (error) return `An error occurred: ${error.message}`;
if (isLoading || !data) return "Loading...";
return <div>{data.title}</div>;
};TIP
You can find more information about createFetchClient on the openapi-typesafe-fetch documentation.