OpenAPI React Query Codegen

repository·main·Indexed 19 days ago

https://github.com/7nohe/openapi-react-query-codegen

A code generation tool that automates the creation of type-safe TanStack Query (React Query) hooks and utility functions from an OpenAPI schema. It generates custom hooks for useQuery, useSuspenseQuery, useMutation, and useInfiniteQuery, along with data-fetching utilities for prefetching and synchronization. The tool leverages @hey-api/openapi-ts to produce TypeScript clients and provides configurable CLI options for input schemas, output directories, and HTTP clients like @hey-api/client-fetch or @hey-api/client-axios.

Tokens
6K
Snippets
22
Records
31
Agent score
64%

What's inside @7nohe/openapi-react-query-codegen

  1. Features of OpenAPI React Query Codegen

    main

    The generator provides several key automation features for React applications:

    • Custom React Hooks: Automatically generates hooks utilizing React Query's core primitives: useQuery, useSuspenseQuery, useMutation, and useInfiniteQuery.
    • Data Fetching Utilities: Generates custom functions that wrap React Query's ensureQueryData and prefetchQuery for efficient data prefetching and synchronization.
    • Query Key Management: Generates structured query keys and query functions to facilitate robust query caching.
    • TypeScript Client Integration: Produces pure TypeScript clients by leveraging @hey-api/openapi-ts.
  2. Key features of OpenAPI React Query Codegen

    main

    The tool provides three main capabilities for building type-safe React applications:

    1. React Query Hooks: Generates custom hooks that wrap TanStack Query's core primitives: useQuery, useSuspenseQuery, useMutation, and useInfiniteQuery.
    2. Prefetching & Router Integration: Generates custom functions utilizing React Query's ensureQueryData and prefetchQuery. This allows for seamless integration with modern frameworks like Next.js and Remix for server-side prefetching or router-based data loading.
    3. Pure TypeScript Clients: Leverages @hey-api/openapi-ts to generate pure TypeScript clients, enabling type-safe API calls even in environments where you are not using React Query.
  3. Manage dependency type patches

    main

    The project uses skipLibCheck: false, meaning type errors in dependency declaration files will fail the build. To manage this, the project uses two mechanisms:

    1. patches/: Contains pnpm patches that add // @ts-ignore to known typing bugs in @hey-api/openapi-ts and @hey-api/shared declaration files.
    2. src/vendor-typestubs.d.ts: Stubs modules referenced by @hey-api/openapi-ts but not installed (e.g., ky, ofetch, nuxt/app, @angular/*).

    How to update patches for @hey-api/openapi-ts

    When upgrading @hey-api/openapi-ts, you must recreate the patches:

    1. Run the patch command for the new version.
    2. Edit the files in the directory printed by the command.
    3. Commit the patch.
    4. Run pnpm build to verify that no declaration errors remain.
    pnpm patch @hey-api/openapi-ts@<new-version>
    # edit the printed directory, then
    pnpm patch-commit <printed-directory>
  4. Run development tasks and validation

    main

    Use the following commands to run tests, linting, and other maintenance tasks:

    • Run tests: pnpm test
    • Run linter: pnpm lint
    • Run linter and fix: pnpm lint:fix
    • Update snapshots: pnpm snapshot
    • Build example and validate generated code: This command builds the project, generates the API in the @7nohe/react-app package, and then runs tests on the generated code to ensure correctness.
    • Preview the docs: Starts the documentation server for the docs package.
    # Build example and validate generated code
    npm run build && pnpm --filter @7nohe/react-app generate:api && pnpm --filter @7nohe/react-app test:generated 
    
    # Preview the docs
    pnpm --filter docs dev
  5. Using the generated `useMutation` hooks and invalidating queries

    main

    Use the generated useMutation hooks (e.g., useAddPet) to perform side effects.

    Important: Cache Invalidation To ensure your UI reflects the changes made by a mutation, you must invalidate the relevant queries using queryClient.invalidateQueries. To ensure the query key is constructed exactly as the hook expects (ensuring correct typing and cache matching), use the exported KeyFn provided for that specific query (e.g., UseFindPetsByStatusKeyFn).

    import {
      useFindPetsByStatus,
      useAddPet,
      UseFindPetsByStatusKeyFn,
    } from "../openapi/queries";
    
    function App() {
      const [status, setStatus] = React.useState(["available"]);
      const { data } = useFindPetsByStatus({ query: { status } });
      
      const { mutate } = useAddPet({
        onSuccess: () => {
          queryClient.invalidateQueries({
            // Use the generated KeyFn to ensure the key matches the hook exactly
            queryKey: [UseFindPetsByStatusKeyFn({
              status
            })],
          });
        },
      });
    
      return (
        <div className="App">
          <button onClick={() => mutate({ name: "Fluffy", status: "available" })}>Add Pet</button>
        </div>
      );
    }
  6. Using the generated `useQuery` hooks

    main

    You can use the auto-generated React Query hooks directly to fetch data. These hooks are typically exported from ../openapi/queries.

    If you need more control, you can use the pure TypeScript SDK functions (defined in openapi/requests/sdk.gen.ts or the openapi/requests/services.gen.ts shim) with the standard @tanstack/react-query useQuery hook. To maintain consistency and type safety, use the auto-generated query key function (e.g., useFindPetsKey) provided by the generated files.

    import { useFindPets } from "../openapi/queries";
    function App() {
      const { data } = useFindPets();
    
      return (
        <div className="App">
          <h1>Pet List</h1>
          <ul>{data?.map((pet) => <li key={pet.id}>{pet.name}</li>)}</ul>
        </div>
      );
    }
  7. Using the generated `useInfiniteQuery` hooks

    main

    The codegen automatically generates infinite query hooks in infiniteQueries.ts if your OpenAPI schema meets two criteria:

    1. A parameter name matches the pageParam option (e.g., page).
    2. A response property name matches the nextPageParam option (e.g., nextPage).

    Configuration Details:

    • initialPageParam: Sets the starting page (defaults to 1).
    • nextPageParam: Supports dot notation for accessing nested values in the response (e.g., meta.next).
    import { useFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";
    
    const { data, fetchNextPage } = useFindPaginatedPetsInfinite({
      query: { tags: [], limit: 10 }
    });
  8. Using the generated `useQuerySuspense` hooks

    main

    The codegen provides suspense-compatible hooks (e.g., useFindPetsSuspense) exported from ../openapi/queries/suspense. These hooks are designed to work with React's <Suspense> boundary, allowing you to handle loading states at a component tree level rather than inside the hook itself.

    import { useFindPetsSuspense } from "../openapi/queries/suspense";
    
    function ChildComponent() {
      const { data } = useFindPetsSuspense({
        query: { tags: [], limit: 10 },
      });
    
      return <ul>{data?.map((pet, index) => <li key={pet.id}>{pet.name}</li>)}</ul>;
    }
    
    function ParentComponent() {
      return (
        <>
          <Suspense fallback={<>loading...</>}>
            <ChildComponent />
          </Suspense>
        </>
      );
    }