OpenAPI Generator typescript-fetch を使う

4 min read読了の目安(約4300字

OpenAPI によって記述された API 定義ファイルをもとに、TypeScript の型や API クライアントを自動生成するというのは一般的に多用されているはずですが、意外に資料が全く見つからなかったのでまとめました。

ぶっちゃけクッソメンドいし、文化圏的にアレなところ多いので、使わなくて済むなら使わないほうがいいです

OpenAPI/swagger

OpenAPI は、もともと API 仕様を JSON/YAML の類で記述して、バックエンドとフロントエンドで共有しようという技術は山程あってその中の一つに過ぎなかった Swagger が発展してデファクトスタンダードになった仕様です。

ソースコード生成

OpenAPI からのソースコード生成のデファクトスタンダードは OpenAPI generator です。

ただし、Java で書かれているため動かすためには Java の実行環境が必須になります。また、このツールは割と癖が強く環境によっては使い物になりません。幸い我らが TypeScript はまだ少しマシなようです。比較的 😇。

OpenAPI Generator は、generator によって複数の出力に対応していて、様々な言語、C, C++, Java, JavaScript, TypeScript その他を吐き出すことができます。

そして、TypeScript の generator では Anguar, AnguarJS, axios, fetch, jquery などに対応したものが存在します。

※ここで注意が必要ですが、typescript の generator という一つのものがあるわけではなくて、typescript-angular や typescrip-axios のような個別の独立した異なる generator がそれぞれ存在していて、それが大きな罠となります。

また、API クライアントだけではなくて、Node.js の express によるモックサーバーも出力できるため、最悪の場合、バックエンド側の開発が遅延していたとしてもモックサーバーでコードの検証ができます。

typescript-fetch を選ぶ理由

axios は容量が大きすぎるので typescript-fetch にしました。

ただ、typescript-axios が生成するコードと typescript-fetch が生成するコードは、それぞれ仕様が全く異なります。初期化の仕方、メソッドの呼び出し方(引数)など異なるため注意が必要です。なんというか無法地帯なのでくじけない心が必要です。

インストール

OpenAPI generator の npm @openapitools/openapi-generator-cli があるため、これをインストールします。

# npm の場合
$ npm i -D @openapitools/openapi-generator-cli
# yarn の場合
$ yarn add -D @openapitools/openapi-generator-cli

インストールが完了すると openapi-generator-cli というコマンドがインストールされるのでこれを叩くことになります。

API クライアント生成

$ openapi-generator-cli generate -g typescript-fetch -i <OpenAPI定義ファイル>  -o <出力先> --additional-properties=modelPropertyNaming=camelCase,supportsES6=true,withInterfaces=true,typescriptThreePlus=true

typescript-fetch を使い、追加パラメータをいくつか指定しています。注意点として modelPropertyNaming=camelCase,supportsES6=true,withInterfaces=true,typescriptThreePlus=true のような形式を必ず守る必要があります。スペースを入れてはいけませんし ,= などの記号は正確に書く必要があります。

  • modelPropertyNaming=camelCase
    • API 仕様は大抵の場合、snake_case で記述されますが、camelCase に自動変換するオプションです。
  • supportsES6=true withInterfaces=true
    • これらのオプションはちゃんと検証してるわけではないですが多分必要そうなので指定しておきました。
  • typescriptThreePlus=true
    • デフォルトだと TypeScript の古いバージョン向けのコードを吐き出して TypeScript エラーになるため、このオプション設定が必須です。

たぶん他にも指定したほうがいいオプションはありそうですが、死ぬほどめんどくさいのであまり突っ込んで調査はしていません。

  • TODO: パラメータがデフォルトでオプショナルになるのを抑制する

コード生成の注意点

コード生成時、もともとあったコードを上書きするだけなので、不要なファイルが残ったままになってトラブルになりがちなので rimraf などをインストールした上で、コード生成の前に不要なファイルを削除することをおすすめします。

モックサーバー生成

$ openapi-generator-cli generate -g nodejs-express-server -i <OpenAPI定義ファイル> -o <出力先>

起動方法は、出力先のディレクトリで npm run start もしくは yarn start です。

起動すると localhost:8080 で起動しているはずです。

typescript-fetch の使い方

API クライアントのクラスは、API のグルーピングで使われる tags ごとに生成されます。たとえば tagsUser であれば UserApi という名前のクラスになります。

VSCode なら Swagger Viewer 拡張 の swagger preview 機能を使うと良いでしょう。

インスタンス生成

import { UserApi } from '<api path>'

const userApi = new UserApi()

これで API クライアントのインスタンスを取得できますが、オプション未指定の場合、API 仕様書に記述されたサーバーに直接つなぎにいくため、開発で使う場合はサーバーを指定する必要があります。

import { UserApi, Configuration } from '<api path>'

const conf = new Configuration({
  basePath: 'API server (ex. http://localhost:8080)',
})
const userApi = new UserApi(conf)

UserApi に直接渡すことはできないため Configuration インスタンスを作成する必要があります。クッソめんどいです

ちなみにこれは typescript-fetch を使う場合です。typescript-axios のコードは、全く使い方が違うため、別途調べ直す必要があります。クッソめんどいです

API アクセス

tagsUser の場合 UserApi クラスのインスタンスを作成する必要がありました。あとはエンドポイントに対応したメソッドを呼び出せば API にアクセスできます。

たとえば、エンドポイントを /api/v1/signup の POST メソッドだとしましょう。その場合呼び出すメソッドは apiV1SignupPost になります。また、このときの引数の型を UserData だったとします。

userApi.apiV1SignupPost({
  userDataBody: {
    ...
  }
})

このようなコードになります。

メソッド名、型名などは、考えるな!感じろ!。自動生成かつ、ドキュメントが皆無なので仕方ありません。一応ルールによって生成されてますが、ドキュメントが皆無なのでなんとなくで調べるしかありません 😇😇😇😇😇😇😇

まとめ

現状だとデファクトスタンダードは Java で書かれた OpenAPI generator であり、その中の typescript-fetch などの generator を使って生成することになるでしょう。ただし、まともなドキュメントは皆無であり、使っていくと様々なトラップに引っかかることでしょう。

くじけない強い心と余裕が必要です。

😇😇😇😇😇😇😇😇😇

ちなみに僕はまだ試してないですが、pure JS なプロダクトもあるようです。