@beta. For v3, read the docs in the v3 branch.Migrating from openapi-react-query
openapi-typescript has entered maintenance mode: no further updates, including security patches. If you use openapi-typescript with openapi-fetch and openapi-react-query, this guide shows how to move to OpenAPI React Query Codegen.
How the two approaches differ
Section titled “How the two approaches differ”| openapi-react-query | OpenAPI React Query Codegen | |
|---|---|---|
| Approach | Runtime wrapper typed by a generated paths type |
Generated, per-operation hooks and queryOptions factories |
| Call style | $api.useQuery("get", "/pets/{id}", ...) — method and path strings |
useFindPetById({ path: { id } }) — one function per operation |
| Fetch layer | openapi-fetch |
Client generated by this package (fetch or axios) |
queryOptions |
$api.queryOptions(...) |
findPetByIdOptions(...) |
SSR (prefetchQuery, ensureQueryData) |
Build it yourself from queryOptions |
Generated for each GET operation |
| Query keys | Derived from method, path and params | Exported key constants and key functions |
| Suspense / infinite | useSuspenseQuery / useInfiniteQuery |
Generated useXxxSuspense / useXxxInfinite / useXxxSuspenseInfinite |
The move is a rewrite of call sites, not a drop-in swap. Hook names come from each operation's operationId, so make sure your schema has stable operationIds.
1. Replace the tooling
Section titled “1. Replace the tooling”npm uninstall openapi-typescript openapi-fetch openapi-react-querynpm install -D @7nohe/openapi-react-query-codegen@betanpx openapi-rq -i ./openapi.yamlKeep @tanstack/react-query 5.x installed. Replace the openapi-typescript step in your scripts with openapi-rq.
2. Replace client setup
Section titled “2. Replace client setup”Before:
import createFetchClient from "openapi-fetch";import createClient from "openapi-react-query";import type { paths } from "./schema";
const fetchClient = createFetchClient<paths>({ baseUrl: "https://myapi.dev/v1/" });export const $api = createClient(fetchClient);After — configure the generated client once, at app startup:
import { client } from "./openapi/requests/services.gen";
client.setConfig({ baseUrl: "https://myapi.dev/v1/" });See the introduction for the exact setup of the client you generate.
3. Replace call sites
Section titled “3. Replace call sites”Parameters are flat: params.path becomes path, params.query becomes query. The request body stays under body.
Queries
Section titled “Queries”Before:
const { data } = $api.useQuery("get", "/pets/{id}", { params: { path: { id: 5 } },});After:
import { useFindPetById } from "./openapi/queries";
const { data } = useFindPetById({ path: { id: 5 } });Or use the queryOptions factory, which composes with any TanStack Query API:
import { useQuery } from "@tanstack/react-query";import { findPetByIdOptions } from "./openapi/queries";
const { data } = useQuery(findPetByIdOptions({ path: { id: 5 } }));Mutations
Section titled “Mutations”Before:
const { mutate } = $api.useMutation("post", "/pets");mutate({ body: { name: "Rex" } });After:
import { useAddPet } from "./openapi/queries";
const { mutate } = useAddPet();mutate({ body: { name: "Rex" } });Query keys and invalidation
Section titled “Query keys and invalidation”openapi-react-query keys its queries by method, path and parameters. A key such as ["get", "/pets"] matches nothing here, so invalidating it leaves the displayed data stale. Use the generated key constant to match every query of an operation, or the key function with the same options as the query to match that one query:
import { useQueryClient } from "@tanstack/react-query";import { useFindPetsKey, UseFindPetByIdKeyFn } from "./openapi/queries";
const queryClient = useQueryClient();
// Every findPets query, whatever its parametersqueryClient.invalidateQueries({ queryKey: [useFindPetsKey] });
// Only the findPetById query made with these optionsqueryClient.invalidateQueries({ queryKey: UseFindPetByIdKeyFn({ path: { id: 5 } }), exact: true,});Infinite queries
Section titled “Infinite queries”Before:
$api.useInfiniteQuery( "get", "/pets", { params: { query: { limit: 10 } } }, { getNextPageParam: (lastPage) => lastPage.nextPage, initialPageParam: 0 },);After — the page parameter is wired by the generator. Pass --pageParam and --nextPageParam to openapi-rq to match your API. The generated hooks start at page 1 by default, so for this example also pass --initialPageParam 0, then:
import { useFindPetsInfinite } from "./openapi/queries/infiniteQueries";
const { data, fetchNextPage } = useFindPetsInfinite({ query: { limit: 10 } });See CLI options and infinite query usage for details.
Server-side prefetching
Section titled “Server-side prefetching”With openapi-react-query you build prefetching yourself from queryOptions. Here each GET operation also gets prefetchQuery and ensureQueryData functions in prefetch.ts and ensureQueryData.ts, and a GET operation with the page parameter also gets a prefetchInfiniteQuery function — see the Next.js example.
What you give up
Section titled “What you give up”- The 1 kb runtime footprint: the generated clients are larger than
openapi-fetch. - Path-string call style. Each operation is its own function, so renaming an
operationIdrenames the hook. - Non-React frameworks: this library targets React only.