Laravelに1行足すだけでOpenAPIを吐き出せるものを作った

この記事は個人ブログと同じ内容です。

kotamat.com

SPA + API構成でLaravelを使っているところも多いかと思いますが、双方の通信のインターフェースを担保するのに皆さんはどうしているでしょうか。

REST APIスキーマ定義としてOpen APIが現在主流かとは思いますが、スキーマ定義言語そのものが最初に作ったら終わりというものではなく、サービスが続く限りメンテナンスをし続けなければならないものであるため、特にサービスロンチ前のプロダクトでは得られる恩恵よりもコストが上回ってしまうために嫌煙されてしまうこともあるかと思います。

一方でOpenAPIを書いておくと、インターフェースから型定義を生成できるため、通常開発以上のコストを払わなくて済むのであれば、ぜひとも導入しておきたいものかと思います。

今回は過去に作った kotamat/laravel-apispec-generator を改修し、1行書くだけでOASjsonファイルを吐き出せるものを作ってみたので紹介します。

https://github.com/kotamat/laravel-apispec-generator

ざっくりとした仕様

LaravelにはPHPUnitを拡張したテストがあり、特に$this->json()ないしはそれの拡張メソッドを使うことによってエンドポイントに対するリクエスト、レスポンスのテストを容易に書くことができます。

今回作ったライブラリは、このテストを通している全エンドポイントに対して、OASを吐き出せるものとなっています。

使い方

個々のテストケースごとにOASを吐き出す

当該パッケージをインストールし

composer require --dev kotamat/laravel-apispec-generator

対象としたいクラスにて、下記のようにuseを差し込むだけです。

class SomeTestCase extends TestCase
{
+    use ApiSpec\ApiSpecOutput\ApiSpecOutput;
    //...
}

その後、テストを実行すると storage/app 配下に各エンドポイントのOAS定義ファイルがjson形式で出力されます。 (例えば http://example.com/api/hoge/fuga へのGETリクエストで200が帰ってくるテストであれば、storage/app/api/hoge/fuga/GET.200.json が書き出されます )

全エンドポイントに集約したOASを吐き出す

吐き出されるものはあくまでそのテストで使用したエンドポイントのOASのみです。OASを使いたいケースは全エンドポイントに対してのOASがほしい事が多いと思うので、今回はartisanコマンドにて、一つのjsonファイルに集約する処理も追加しました。

集約する場合は

php artisan apispec:aggregate

を実行すると、上記で生成したjsonファイルを読み込み storage/app/all.jsonOASを吐き出します。

集約する際は、リクエスURI、HTTPメソッド、レスポンスのステータスコードごとにユニークなものを集計します。もし同じリクエスURI、HTTPメソッド、レスポンスのステータスコードのテストがある場合は、あとから実行されたもので上書きされます。

(今後は anyOf とかを使って複数のリクエストボディ、レスポンスボディで使えるようにしたいとは思っているが、codegen側で不具合があり、適切な型定義が吐き出せなかった。)

生成されたOASはどうする?

jsonの中身をSwaggerEditorにコピペしてみるのもいいし、下記コマンドをLaravelのルートディレクトリで実行してみてTypeScriptの型定義をだしてみるのもいいかなと思います。

target=storage/app/all.json

docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate -i /local/${target} -g typescript-fetch -o /local/dist

まとめとか

今回はLaravelのフィーチャーテストからOASを吐き出すパッケージに関して紹介させてもらいました。 このパッケージを使えば追加メンテ工数ほぼゼロでOASの運用ができるようになるかと思います。興味あればぜひ使ってみてください。

正直8時間くらいで作ったものというのもあり、現状まだ全仕様を網羅しているわけではないため、もしかしたらエラー出ちゃうところもあるかもしれないです。修正したほうがいいところあれば気軽にPR出してもらえると嬉しいです。