Skip to content
These docs describe v4, which is in beta: install it with @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.

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.

Terminal window
npm uninstall openapi-typescript openapi-fetch openapi-react-query
npm install -D @7nohe/openapi-react-query-codegen@beta
npx openapi-rq -i ./openapi.yaml

Keep @tanstack/react-query 5.x installed. Replace the openapi-typescript step in your scripts with openapi-rq.

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.

Parameters are flat: params.path becomes path, params.query becomes query. The request body stays under body.

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 } }));

Before:

const { mutate } = $api.useMutation("post", "/pets");
mutate({ body: { name: "Rex" } });

After:

import { useAddPet } from "./openapi/queries";
const { mutate } = useAddPet();
mutate({ body: { name: "Rex" } });

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 parameters
queryClient.invalidateQueries({ queryKey: [useFindPetsKey] });
// Only the findPetById query made with these options
queryClient.invalidateQueries({
queryKey: UseFindPetByIdKeyFn({ path: { id: 5 } }),
exact: true,
});

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.

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.

  • 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 operationId renames the hook.
  • Non-React frameworks: this library targets React only.