背景
今やWebだけでなく、iOS、Android、TV、カーナビといった多数のクライアントでAPIを利用する時代です。
各クライアントでBFFを置く設計もありますが、開発コストや運用コストを考えて同一のAPIサーバを用意し利用することも多いと思われます。
加えてサービスが大きくなってくると外部企業との連携や有志の開発者のためにAPIを公開するケースもあります。
そういった状況下では単にドキュメントベースでやり取りするのは難しく、しばしばAPIとドキュメントの乖離が生まれ負債となっていきます。
そのためこれらの問題を解決できる
- JSON Schema
- Protocol Buffers
- OpenAPI Specification
といったスキーマ言語の活用がとても重要になってきます。
今回はOpenAPIについて話します。
他のスキーマ言語の問題点は?
まずOpenAPI以外のスキーマ言語で起きる問題点を話します。
JSON Schemaのデメリット
JSON Schemaは拡張型もありValidation等も定義でき、連携ツールも多種ありとある程度エコシステムも整っています。なのでスキーマを表現をする上では十分な機能を備えています。
しかしながら
3ヶ月ばかり開発して、その過程でそれなりに大きくなったSchemaをいじくり回して、6ヶ月ほど他の場所を見て回って、ある日そのコードに戻ってきたとしよう。
半年ぶりに見たそのJSON Schema、本当に一瞥して何が書いてあるか理解できるんだろうか。
今さらProtocol Buffersと、手に馴染む道具の話 - Qiita
この話の通りで、僕自身も同じ経験をしました。
数ヶ月ぶりに見たスキーマを理解するのがしんどく、また新しいメンバーにとっても非常に学習コストのかかるものでした。
Protobufのデメリット
Protobufの場合は大体がメッセージ構造のみを定義していく形で、JSON Schemaに比べて覚えることも少なく先程のような問題は起きにくいです。
gRPCのServiceを定義するのも4つのRPC方式があるだけですんなり書けると思います。
しかしREST APIの場合はgrpc-gatewayのoption記述があるとはいえ
- 認証関連の設定
- ヘッダー情報
- クエリパラメータなのかbodyなのかの区別
あたりが苦しくなってきます。頑張って盛り込んでいくとそれはそれで先のJSON Schemaと同じ道をたどります。
なのでREST APIの場合はメッセージ構造の定義に留めて、あとは別のところ(ドキュメントなり)でカバーという選択肢も1つです。
OpenAPI(旧Swagger)
ではOpenAPIについて話していきます。
メリット
まずメリットとして
- デファクトスタンダードになってきてること
- エコシステムが整っていること
これらが大きいと思います。
デファクトスタンダードになってきてる
Linux Foundation、Google、IBM、Microsoftなどのそうそうたる企業が仕様策定に関わってます。
Swaggerを買収したSmartBear社との対立も影響し?コミュニティ活動も非常に活発です。
エコシステムが整っている
に一覧がありますが、
など、必要なものがほぼ揃うと思います。
デメリット
Protobufのように表現上の制限はないです。
一方でJSON Schema同様表現豊かに作れるので、その分学習コストも増大します。
しかし先程のエコシステムで話したようなヘルパーツールが多数あるため、その問題点を解決しています。
次に説明していきます。
各種ツール
ほとんどこちらの記事で紹介されている通りです。
本当に使ってよかったOpenAPI (Swagger) ツール | Future Tech Blog - フューチャーアーキテクト
Stoplight Studio
Stoplightが出しているGUIエディタです。
各プラットフォームでアプリがあり、Webエディタも提供されてます。
こんな感じにサクサクとGUIでプレビューを見ながら作れます。
GUIで表現できない場合はコードを直接いじることもあります。
文法エラーや抜け漏れがある場合は逐次指摘してくれます。
Stoplight Prism
Stoplight Prismはモックサーバです。先程のStudioにも標準で入っています。
OpenAPIのモックサーバは多々ありますが、これの良い点は
- Dockerで簡単に起動できる
- Dynamic Responseに対応している
の2点です。
Dockerで簡単に起動できる
$ docker run --rm -it -p 4010:4010 \ stoplight/prism mock -h 0.0.0.0 \ 定義ファイルorURL
とすると起動できます。
Dynamic Responseに対応している
-d
オプションを付けるとレスポンスがランダムに生成されます。
わざわざ自分でテストデータを用意する必要がありません。
$ docker run --rm -it -p 4010:4010 \ stoplight/prism mock -h 0.0.0.0 -d \ https://petstore.swagger.io/v2/swagger.json
curlで叩いてみます。
$ curl -s -X GET "http://localhost:4010/pet/123" -H "accept: application/json" -H "api_key: foo" | jq . { "name": "elit in deserunt dolor", "photoUrls": [ "quis cillum anim i", "deserunt", "adipisicing" ], "id": 58711555, "category": { "id": 56698318, "name": "elit" }, "tags": [ { "id": -2228071, "name": "qui nulla reprehenderit" }, { "id": -9457690, "name": "aliqua consectetur nulla est" }, { "id": -13096371, "name": "Excepteur tempor irure pariatur" }, { "id": 91905868, "name": "laborum sit anim" } ], "status": "pending" }
中身はfaker.jsなので、データモデルにx-faker
というフィールドを追加してformat指定するとそのフォーマットで生成してくれます。
フォーマットの種類とどんな値が生成されるかは以下を参考にするといいです。
faker.js - generate massive amounts of fake data in node.js and the browser
このモックサーバを立てておけば、クライアントはサーバ側の実装を待つ必要なく開発に着手できます。
Swagger UI
ドキュメントツール(サーバ)です。OpenAPIのスキーマを渡すと自動でドキュメント生成してくれます。
Swagger UI | API Development Tools | Swagger
こんなUIです。
正直UIはslateとかの方が好みです。こんなふうになります↓
slateフォーマットへの変換ツールもあるので余裕があれば、でしょうか。
ローカル開発
先程のツール群を使い、以下のようなdocker-compose.ymlを用意してローカル開発をしやすくしています。
version: "3" services: swagger-ui: image: swaggerapi/swagger-ui volumes: - ./reference/api.yaml:/docs/api.yaml environment: SWAGGER_JSON: /docs/api.yaml ports: - "8080:8080" mock-api: image: stoplight/prism volumes: - ./reference/api.yaml:/docs/api.yaml command: mock -h 0.0.0.0 /docs/api.yaml ports: - "4010:4010"
逐次ドキュメントとしてどう表示されるかを確認しつつ、モックサーバで動作を確認できます。
まとめ
OpenAPIのエコシステムにうまく乗っかると、REST APIの効率的な開発ができるようになると思います。