OpenAPIスキーマからReact Query(TanStack Query)のHooksコードを自動生成する

Aug 9, 2022

はじめに

OpenAPIスキーマからReact Query(TanStack Query)のカスタムHooksコードを自動生成できるライブラリを作ってみたので紹介します。

React Query(TanStack Query) はAPIリクエストが多く発生するアプリケーションでの状態管理にはとても便利なライブラリです。 例えば書き方としては以下のようになります。

import { useQuery } from '@tanstack/react-query'
import { getTodos } from '../my-api'

function Todos() {
  // Queries
  const query = useQuery(['todos'], getTodos)
  return (
    <div>
      // something
    </div>
  )
}

上記のようにAPIリクエスト関数のimportとtodosのようなQuery Keyの設定を毎回する必要があり少々面倒です。

そこでOpenAPI Typescript CodegenでTSクライアント生成時と一緒に自動で生成されたTSクライアントからのAPIリクエスト関数とQuery Keyが設定されたカスタムHooksコードを生成できないかと考えこのライブラリを作りました。

このライブラリで生成したHooksを使うと先ほどのコードが以下のようになります。

import { useTodoServiceGetTodos } from "../openapi/queries";

function Todos() {
  // Queries
  const query = useTodoServiceGetTodos()

  return (
    <div>
      // something
    </div>
  )
}

地味ですがimport文が一つなくなり、文字列で書いていたQuery Keyが自動で設定されます。

特徴

このライブラリの特徴としては以下です。

  • OpenAPIスキーマからReact Query(TanStack Query)のカスタムHooksコードを自動生成できる
  • OpenAPI Typescript CodegenのTSコードも一緒に生成されるので、必要に応じてReact Queryを使わない書き方もできる

インストール

$ npm install -D @7nohe/openapi-react-query-codegen

使い方

コード生成

openapi-rq コマンドを使ってコードを生成します。

例えばpetstore.yamlというOpenAPIスキーマファイルがあったとします。

$ openapi-rq -p ./petstore.yaml

生成されたコードの構成

デフォルトではopenapiというフォルダが作られそこにqueriesrequestsが作られます。 queriesはReact QueryのカスタムHooksが置かれ、requestsにはOpenAPI TypeScript Codegenで生成されたファイルが置かれます。

- openapi
  - queries
    - index.ts <- custom react hooks
  - requests <- output code generated by OpenAPI TypeScript Codegen

生成されたコードの例

例えば以下のようなスキーマファイルだったとします。

.
.
paths:
  /pets:
    get:
      description: Returns all pets
      operationId: findPets
      parameters:
        - name: tags
          in: query
          description: tags to filter by
          required: false
          style: form
          schema:
            type: array
            items:
              type: string
        - name: limit
          in: query
          description: maximum number of results to return
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

生成されるコードは以下のようになります。

import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { DefaultClient } from "../requests/services/DefaultClient";
export const useDefaultClientFindPets = ({ tags, limit }: {
    tags: Array<string>;
    limit: number;
}, queryKey: string[] = [], options?: Omit<UseQueryOptions<Awaited<ReturnType<typeof DefaultClient.findPets>>, unknown, Awaited<ReturnType<typeof DefaultClient.findPets>>, string[]>, "queryKey" | "queryFn" | "initialData">) => useQuery(["DefaultClientFindPets", ...queryKey], () => DefaultClient.findPets(tags, limit), options);

生成したコードの使用例

生成したコードはReactアプリ内で以下のように使えます。

import {
  usePetServiceFindPetsByStatus,
} from "../openapi/queries";
function App() {
  const { data } = usePetServiceFindPetsByStatus({ status: ["available"] });

  return (
    <div className="App">
      <h1>Pet List</h1>
      <ul>
        {data?.map((pet) => (
          <li key={pet.id}>{pet.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

このようにAPIリクエスト処理を少ないコード量で書くこともでき、React Queryでの状態管理も行うことができます。

また、カスタマイズしたいときもOpenAPI TypeScript Codegenで生成されたコードをそのまま使ってもOKです。

import { useQuery } from "@tanstack/react-query";
import { PetService } from '../openapi/requests/services/PetService';
function App() {
  const { data } = useQuery(['MyKey'], () => {
    // Do something here

    return PetService.findPetsByStatus(['available']);
  });

  return (
    <div className="App">
      {/* .... */}
    </div>
  );
}

export default App;

おわりに

いかがでしょうか?OpenAPIスキーマからそのまま使えるReact Queryコードが生成されるのは結構良いんじゃないかなと思っています。 今後はテストなどで使えるモックレスポンスを返すHooksコードも一緒に生成できればなと考えています。 気になった方は是非使ってみてください。