OpenAPI generatorとは

OpenAPI generatorとは、OpenAPI Specificationに従ってAPIの仕様を記述することで、APIクライアントを自動生成できるツールです。 たとえば、OpenAPI Specificationのサンプルとして公開されているペットショップのAPI仕様を用いて、PHP用のAPI Clientを作ってみるコマンドは下記のようになります。

npm init
npm install --dev openapi-generator-cli 
openapi-generator-cli generate -g php -i https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml

生成されたコードはこちらです。 https://github.com/77web/openapi-generator-php-template-demo/tree/default

APIに送信するリクエスト値とAPIから返ってくるレスポンス値はオブジェクトとして表されており、APIへのHTTPアクセスの詳細は隠蔽されています。

<?php
$pets = $apiClient->listPets();
foreach ($pets as $pet) {
    /** @var \OpenAPI\Client\Model\Pet $pet */
    $pet->getName();
}

一般的なRESTful APIへのアクセス用途であれば、世界中の開発者によってデバッグされテストされているコードをそのまま自分のアクセスしたいAPI用に使うことができるのが魅力です。 OpenAPI Specification定義さえあれば(あるいは、書ければ)、自力で専用のApiClientを作ったりメンテナンスしたりする必要のなくなる強力なツールと言えます。

特にカルテットが利用している広告媒体のAPIには、PHP向けのApiClientが公式から提供されていない場合があり、年に3〜4回アップデートされていく広告媒体APIに対して多数のApiClientを自力でメンテナンスするのはつらいので、とても助かっています。

PHP8.1でOpenAPI generatorのApiClientを使うときに困る点

便利なOpenAPI generatorですが、PHP8.1でOpenAPI generatorに生成させたApiClientを使うときには若干困る点があります。 #[ReturnTypeWillChange] をつけろという大量のdeprecation noticeが出たり(最近修正されました)、enumがPHPのネイティブenumでなくクラス定数としての定義だったりします。 とはいえ、generatorで提供するのが汎用的なApiClientである以上、自社がもうPHP8.1を使っているからと言って、まだサポートの切れていないPHP7.4やPHP8.0を使っているプロジェクトを切り捨てるわけにいかないことは理解できます。

OpenAPI generatorのカスタムテンプレート機能を使う

0penAPI generatorにはカスタムテンプレート機能 https://openapi-generator.tech/docs/templating/ があり、公式テンプレートと同じ分岐・同じ変数を使う範囲で、生成されるPHPのコードを自分好みに変更することができます。 (実はテンプレートのみならずジェネレーター部分も作ることができるのですが、お手軽とは行かないので今回はテンプレートのカスタムのみにとどめています)

OpenAPI generator用のテンプレートは mustache というテンプレート言語を用いて書かれています。 https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/php に公開されている公式テンプレートをもとに、 PHP8.1用のカスタムテンプレートを作ってみました。
https://github.com/77web/openapi-generator-php81-templates

実際に社内で利用しているApiClientに適用して使っていますが、今までと利用側コードもほぼ変わらずにPHP8.1のnative enumが利用でき、deprecation noticeも減って快適になりました。

使い方

npmパッケージとして取り込んだあとで、 -t でテンプレートのパスとしてnode_modulesの下にあるテンプレートのディレクトリを指定します。 ※ テンプレート自体をcomposerパッケージにしてしまうとApiClient自動生成時にOpenAPI generatorで上書きされてしまうため、特に何もnode.jsのコードは含んでいませんがnpmパッケージとしています。

npm install --dev "77web/openapi-generator-php81-templates#v1.0.2"
openapi-generator-cli generate -g php -i https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml -t node_modules/quartetcom-openapi-generator-php81-templates/templates

カスタムテンプレートで生成したコードはこちらです。 https://github.com/77web/openapi-generator-php-template-demo/tree/use-php81-custom-template

注意点

カスタムテンプレートを使う場合、世界中で利用されているコードが利用できるという利点は捨てることになりました。 OpenAPI generator公式のテンプレートにも過去にバグはあったのですが、カスタムテンプレートを使ったときは本番適用前に実際にAPIにアクセスするテストを十分に行う必要があるでしょう。

まとめ

外部・内部ともにAPIを使って通信するシステムが増えていく時代、新しいAPIへのアクセスする機能を高速に実装したいとき、OpenAPI generatorは強力な武器になります。 私も以前はかゆいところに手が届く自作ApiClientをすべてのAPIに対していちいち作っていましたが、大半をOpenAPI generatorで自動生成し、一部の特殊なAPIやOpenAPI Specificationがそのまま適用できないAPIへのアクセスのみ自前でClientを書くことで、新しいAPIへの対応期間をかなり短縮できています。 これからも積極的に活用していこうと思います。