Web API のドキュメンテーションって結構めんどくさい。 どういうフォーマットで書くか悩むし、書いていくと似たような内容を何回も繰り返すことになる。 ドキュメントとは別に開発用のモックも用意しなきゃいけなくて、それとの整合性が…ってな具合に悩みは尽きない。 そんなとき今回紹介する API Blueprint を使うとそういった悩みを減らすことができるかもしれない。
今回使う環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.11.3 BuildVersion: 15D21
API Blueprint
API Blueprint というのは Web API (特に RESTful API) の仕様を記述するための言語仕様を指している。 ただし、これは単なる Markdown で書かれた文章を Web API の仕様書として解釈するための仕様にすぎない。 これで Web API の仕様を書いておくと、そこからドキュメントとかモックサーバまで生成できちゃう優れものになっている。
処理系
API Blueprint はあくまで仕様なので、それを解釈する処理系は別にある。 今回は Node.js を使った実装の aglio と api-mock を使うことにする。 aglio はドキュメントを生成できて api-mock はモックサーバを作れる。 ポイントは、それらがひとつの API Blueprint で書かれたファイルから作れること。 これによってドキュメントとモックサーバの整合性に悩む必要がなくなる。
aglio と api-mock をインストールする
まずは Homebrew を使って Node.js をインストールする。
$ brew install node
インストールするとパッケージマネージャの npm コマンドが使えるようになる。 install サブコマンドでグローバルに aglio と api-mock をインストールしよう。
$ npm install -g aglio api-mock
これでシステムに aglio と api-mock がインストールされた。
$ npm -g list | grep aglio ├─┬ aglio@2.2.0 │ ├─┬ aglio-theme-olio@1.6.2 $ npm -g list | grep api-mock ├─┬ api-mock@0.3.2
同時に aglio コマンドと api-mock コマンドが使えるようになる。
$ aglio --version aglio 2.2.0 olio 1.6.2 $ api-mock --version api-mock v0.3.2
API Blueprint で書かれた仕様書を用意する
まずはすごくシンプルな API Blueprint で書かれた仕様書を書いてみる。 中身はただの Markdown だし、見るだけでどういう風に書くのかなんとなくの雰囲気はつかめると思う。 簡単に解説しておくと /message に GET メソッドを実行すると Content-Type が text/plain で “Hello, World!” というメッセージが返ってくる。
$ cat << 'EOF' > helloworld.md # GET /message + Response 200 (text/plain) Hello, World! EOF
ドキュメントを生成する
次に aglio コマンドで先ほど用意したファイルを HTML に変換してみる。
$ aglio -i helloworld.md -o helloworld.html
HTML ファイルができるのでブラウザで開いてみよう。
$ ls | grep html$
helloworld.html
$ open helloworld.html
すると、なんか良い感じの見た目で Web API のドキュメントができている! すばらしい!
ちなみに内容を確認しながら編集するときは aglio コマンドに -s オプションをつけて実行するのがおすすめ。
$ aglio -i helloworld.md -s
こうすると aglio が Web サーバを起動して変換した静的な HTML をホストしてくれる。 もちろん元の .md ファイルに変更があったときはビルドし直して表示してくれるという便利機能付き。
$ open http://127.0.0.1:3000/
その他、つかえるオプションは aglio の公式ドキュメントを参照のこと。
https://github.com/danielgtaylor/aglio#executable
モックサーバを用意する
次はモックサーバを用意してみよう。 といっても事前準備は既にすべて終わっている。 やることは api-mock コマンドに先ほどの .md ファイルを渡すだけ。
$ api-mock helloworld.md
info: Enabled Cross-Origin-Resource-Sharing (CORS)
info: Allow-Origin: *
info: Allow-Methods: GET, PUT, POST, PATCH, DELETE, TRACE, OPTIONS
info: Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, Referer, Prefer
info: Listening on port 3000
これで localhost:3000 でモックサーバが起動する。 試しに curl で叩いてみよう。
$ curl http://localhost:3000/message
Hello, World!
ばっちり。
書き方の例
ここからは API Blueprint をどう書けばいいかの例を示していく。 尚、元ネタについては API Blueprint の仕様書をあたってもらいたい。
API Blueprint Specification | API Blueprint
API の説明を書きたい
API の説明を書きたいときはセクションの合間にちょいちょいと書けばいい。
# GET /message こんにちは世界! + Response 200 (text/plain) Hello, World!
API 自体に説明をつけたいときは HTTP のリクエストをブラケットの中に入れて、説明をその左側に書く。
# 挨拶する [GET /message] + Response 200 (text/plain) Hello, World!
JSON を扱いたい
ここまでの例では Content-Type が text/plain のものを扱ってきた。 最近の Web API なら表現には JSON を使うことが多いはず。 そのためには、まずは Response セクションの括弧内を application/json にする。 その上で Body セクションを JSON で書こう。
# GET /message + Response 200 (application/json) { "message": "Hello, World!" }
ちなみに Content-Body の内容は上記のように直書きしなくても Attribute セクションに書くこともできる。 というより、こちらのやり方がおすすめ。 「<変数名>: <サンプル値> (<型>) - <説明>」という具合に書く。
# 挨拶する [GET /message] + Response 200 (application/json) + Attribute + message: Hello, World! (string) - メッセージ
何故かというと、こうしておけば aglio が Content-Body と一緒に JSON Schema の定義も一緒に作ってくれるから。
便利だよね。
メタデータを追加する
ちなみに API Blueprint はドキュメントの先頭がメタデータセクションという場所になっている。 メタデータには、例えば将来的な拡張などに備えてバージョンのような情報を記載する FORMAT などがある。 厳格に書くのであれば現在のバージョンである 1A を指定しておこう。 他には API を提供するサーバのホストを HOST として書くこともできるようだ。
FORMAT: 1A HOST: http://localhost/ # 挨拶する [GET /message] + Response 200 (application/json) + Attribute + message: Hello, World! (string) - メッセージ
リクエストボディのあるメソッドを扱う
POST や PUT のようにリクエストに色々と情報が必要なメソッドには Request セクションを書く。 また、何らかのヘッダが必要なときは Headers セクションを追加する。
# ユーザを追加する [POST /users] + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 201 (application/json) + Headers Location: /users/1 + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
変数を含むリソースを扱う
これまでに扱ってきたのは、すべてリソース (要するに URI) が静的なものだった。 もしリソースの中に変数が登場するときは波括弧を使ってそれを表現する。 変数の内容については Parameters セクションに説明を書いていく。
# ユーザの情報を更新する [PUT /users/{id}] + Parameters + id: 1 (number) - ユーザの識別子 + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 200 (application/json) + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
上記はパス文字列だったけどクエリ文字列のときは波括弧の先頭に「?」をつける。
# ユーザの情報を更新する [PUT /users/{id}{?token}] + Parameters + id: 1 (number) - ユーザの識別子 + token: 18ede970... (string) - CSRF トークン + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 200 (application/json) + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
複数の API をリソースグループとしてまとめる
複数の API をグルーピングしたいときは # を使う。 例えばユーザを操作する一連の API をまとめてみよう。
# ユーザ関連 API ## ユーザを追加する [POST /users] + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 201 (application/json) + Headers Location: /users/1 + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名 ## ユーザの情報を更新する [PUT /users/{id}] + Parameters + id: 1 (number) - ユーザの識別子 + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 200 (application/json) + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
グループにリソースを紐付けて書くこともできる。 その場合は、個別の API には HTTP メソッドだけを書く。
# ユーザ関連 API [/users/{id}] ## ユーザを追加する [POST] + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 201 (application/json) + Headers Location: /users/1 + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名 ## ユーザの情報を更新する [PUT] + Parameters + id: 1 (number) - ユーザの識別子 + Request (application/json) + Attribute + name: Mr. World (string) - ユーザ名 + Response 200 (application/json) + Attribute + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
Attribute を変数にする
何度も Attribute に似たような内容を書くのが面倒くさいときは Data Structure セクションに分割した内容を参照できる。
# ユーザ関連 API [/users/{id}] ## ユーザを追加する [POST] + Request (application/json) + Attribute (User) + Response 201 (application/json) + Headers Location: /users/1 + Attribute (UserWithID) ## ユーザの情報を更新する [PUT] + Parameters + id: 1 (number) - ユーザの識別子 + Request (application/json) + Attribute (User) + Response 200 (application/json) + Attribute (UserWithID) ## Data Structure ### User + name: Mr. World (string) - ユーザ名 ### UserWithID + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
これは Content-Body の内容が入れ子構造になっているときにも便利に使える
# ユーザ関連 API [/users/{id}] ## ユーザを取得する [GET] + Response 200 (application/json) + Attribute (Users) ## Data Structure ### Users + results (array[UserSummary]) - ユーザのサマリーを格納した配列 ### UserSummary + id: 1 (number) - ユーザ識別子 + name: Mr. World (string) - ユーザ名
とりあえず、これくらい覚えておけば大体の Web API は表現できるかな?
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る