アプリから叩くサーバーのAPIがOpenAPIの形式で定義してくれていることがある。これはめちゃくちゃありがたい。openapi-generatorでクライアントコードを出力することもできるし、なにか問題があればSwagger UIやRedoclyで便利に閲覧したり、Prismでモックサーバーを立てて簡易的に試すこともできる。
できるのだが、毎回調べていて、なんかみんなもっと便利な方法でやってておれだけ不効率なことやってたらどうしようと思う。なんかそういうわけでもなさそうな実感が得られてきたので、雑にまとめる。ここらへん不満なく日常的ににこなしている方はとくに得られるものはないと思うのでブラウザバックいただいたほうがいいかもしれない。
Redocly で閲覧する
npm i -g @redocly/cli@latest redocly preview-docs openapi.yaml
yamlファイルを与えてやるとローカルにサーバーが立ち上がってブラウザで見れるようになる。このとき、bundle.yamlのほうを渡してやると良い。個人的にここ数年?でよく聞くようになったツール。ローカルで見る場合も npm で簡単に入って、セットアップの手間も考えると一番ヘルシーかも。
ただあんまり慣れていなくて読みづらい。表示が急に右側とかに出たりするので、目が滑って情報を取りこぼすことが多く、あと余白もスカスカなのでSwaggerに比べてあんまり良いUIだとも正直思えない。なので個人的には後述のSwaggerを使いたい。
Swagger で閲覧する
VS Codeの拡張機能を入れる方法とdistというのを使ってブラウザで見る方法がある。
VSCodeの拡張機能を入れる
一緒に働いている方に教えてもらったのだが VSCode の拡張があるようで、これはとにかく拡張をインストールしてbundle.yamlを開くだけでOKなので、セットアップが簡単でよかった。
が、yamlを開いているリポジトリが分かれているため開きに行くのがやや億劫、cmd+Fで検索をかけたいときがあるが効かなかった(もしかすると拡張機能上でも使えるのかもしれないが、なぜか反応しなかった)ため、後述する手元でブラウザで見る方法も調べた。
ブラウザで閲覧する
個人的にはこの方法で見たいのだが、調べたところなぜか割と手間というか、回りくどい。
上記の記事を参考に、swagger-ui-distというhtmlとjsなどがセットになったファイル群を、GitHubから入手するか、swagger-ui-dist を npm install でできた node_modules 内のフォルダをまるっとコピーしてきて、bundle.yamlを同じフォルダに格納して、scriptのとこに以下を足す。この内容はindex.htmlか、そこでロードされているjsにある。
+ <script>
+ window.onload = () => {
+ window.ui = SwaggerUIBundle({
+ url: '../bundle.yml',
+ dom_id: '#swagger-ui',
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIStandalonePreset
+ ],
+ layout: "StandaloneLayout",
+ });
+ };
+ </script>
Prism でモックサーバーを立てて実装をたしかめる
APIのクライアントコードの妥当性を検証する必要がある場合はもはや少ないかもしれない。最近はDartのopenapi-generatorを使ってるケースも多い。一方で、古くからやってるプロジェクトには入っていないこともあるし、新しいプロジェクトでもopenapi-generatorがカバーしきれていない仕様のバグとかにあたって採用を見送ったりする場合があり、クライアントコードを手書きする機会もまだある。
最後まで手元で動作確認できればいいのだが、先んじてAPIクライアントの部分だけ準備したいという場合もある。その場合、実装がうまくいっているかどうかチェックする方法があい。生成AIのアシストがある程度あるとはいえ、自分の注意力でバグり散らかしたコードをコードレビューに出すのをできるだけ避けたく、実装をたしかめる方法が必要と感じた。
調べるとprismというツールがあるらしいので使ってみる。
npm install -g @stoplight/prism-cli prism mock openapi.yaml --port 4010
上記でモックサーバーが立ち上がる。わかりやすい。 -v --trace をつけると細かくログを出してくれる。あと --dynamic オプションを付けると、OpenAPIの型定義に沿って毎回ランダムなダミーデータが生成されたり、--errorsでエラー返すようにしてくれたりもするらしいが、これは試せていない。
dart 側から叩くテストに関してはここは生成AIに書いてもらう。このAPIクライアントを使って192.168.1.100:4010にサーバーが立っているとして、あとなんでもいいのでBearerトークンをつけてください…みたいにお願いする。ためしにCopilot Editで出力したRetrofitやfreezedのクライアントやモデルコードをPrismを使ってチェックしてみたところ…全然間違っててワロタw いや生成AIが悪いみたいに言ってますけどわいの指示と目grepが悪いんすよね…
パスは間違えやすいところなのでこれでチェックできるのはありがたい。レスポンスのキー名や型に関しても、違う場合はモデルのパースに失敗するから気付ける。リクエストに関しては、デフォルトでoptionalなのは無視されるのと内容は(おそらく)見てくれないので、あんまり期待できない。グローバルで設定する方法はないが、スキーマに additionalProperties: false を足せばPrism が存在しないキーを含むリクエストを自動的に 400 等のバリデーションエラーとして返すようになるので、キー名についてはこれで気づけそうだが、これはめんどくさい…。
生成AIさんには、あとでbaseUrlに一括で/v1ってつけるのでクライアントに/v1つけるのはやめてください、みたいな話だとか、snake_caseからcamelCaseへの変換はグローバルに設定が定義されているから不要ですみたいな話だとか、伝えているはずなんだけど、意外と難しいようですな…まああっしの仕事がわずかながら残ってたようで良かったですわ…
総括
生成AIでのコード生成でRetrofitやfreezedのクライアントやモデルコードを一発で出すのは意外とまだ難しい。open-api-generatorなどを使うのがやはり一番良いと思うが、ポリモーフィズムの機能(oneOf, anyOf, allOf)のサポートがまだ完全に行われておらず、まだissueがOpenになっている。たとえばひとつのフィードで色々な型のオブジェクトが流れてくるみたいなのをスキーマ定義したいときに、この機能はぴったりなわけなのだが、少なくともDartだと問題のあるコードが生成される。 freezedを使えばUnionで実装することができる。
個人的に精査できているわけではないが、ワークアラウンドとしては上記の記事にあるようなところを守ればopen-api-generatorに合わせることができそう。「open」がプログラミング言語の予約語と被っていてうまくいかない、みたいなところもハマりどころだと思う。