狠狠撸

狠狠撸Share a Scribd company logo
APIドキュメンテーションツールを使い
こなす【Api Blueprint編】
自己紹介
権藤尚樹
2015年5月に株式会社ビズリーチに入社
求人検索エンジン「スタンバイ」 (https://jp.stanby.com) のエンジニ
アやってます
普段の業務ではScalaを書いてます
Webアプリケーションエンジニア歴は3年半ぐらい
将棋と一人旅が趣味
前回の発表
こんなに便利!今どきのAPIドキュメンテーションツール(https://d-
cube.connpass.com/event/43057/)
SwaggerとApi Blueprintの比較に重きを置いた内容でした
目次
1. APIドキュメントの概要
2. Api Blueprintについて
3. Api Blueprintの記法
4. Api Blueprintを支えるツール
5. プロジェクトに導入した話
本日のゴール
Api Blueprintについて知ってもらう
Api Blueprintでいい感じのAPIドキュメントを作れるようになる
Api 叠濒耻别辫谤颈苍迟を用いて开発を(なるべく)楽にできるようになる
サンプルコード
https://github.com/n-gondo123/api-blueprint-example
スライドで紹介するサンプルの内容と若干違うところもあります
が、ご了承ください
1. APIドキュメントの概要
APIドキュメントをつくる目的
APIサーバーに求められるもの
Request/Response
REST API
誰がどういう目的で使うのか
利用する側: どのように使えば良いのか
提供する側: 提供したいものが正しいかどうか
APIドキュメントに書くこと
HTTPリクエスト?レスポンス
URI (host, path, query, ...)
Http Method (GET, POST, PUT, DELETE, ...)
Header (Content-Type, Accept, ...)
Body (json, xml, ...)
schema
Authorization, Authentication
APIドキュメントに書くこと
APIの概要?注意点
APIが返すステータスコードの補足
200系、400系、500系
API固有の仕様
コード値の意味
Custom Validation
2. Api Blueprint
Api Blueprintとは
公式(https://apiblueprint.org/)
「A powerful high-level API description language for web APIs」
APIドキュメントの記述に特化した言語
拡張子は.apibだが、.mdのほうが便利なことが多い
syntax highlightingが効く
Markdown previewが効く(特にgithub)
.mdで困ることは殆どないので、個人的にはこちらを推奨
Api Blueprint vs Swagger
Github (https://github.com/apiaryio/api-blueprint)
Star数は5,539 (資料作成時)
Swaggerツール群(https://github.com/swagger-api) と比べると
Swagger Spec cationよりは覚えることは少ないし、導入の敷居も
低い(個人的な感想)
Swaggerについての話はまたの機会に
3. Api Blueprintの記法
Api Blueprint Speci cation
ドキュメント
(https://apiblueprint.org/documentation/speci cation.html)
幾つかのSectionで構成されている
一部拡張Markdown書式があるが、プレーンなMarkdownとしても十
分読める
MSON(後述)の知識がなくても使えるが、基本的にはセットで覚える
必要がある
Section Structure (Header-de ned)
ヘッダータグの深さは特に気にしなくて良いですが、sectionはネスト
関係にあるのでそこだけ意識すると良いです
# API共通仕様
<ここに説明を書く>
# Group ユーザー
<ここに説明を書く>
## ユーザー一覧の取得 [GET /users/]
<ここに説明を書く>
Section Structure (List-de ned)
インデントは4スペース推奨
+ Request (application/json)
<ここに説明を書く>
+ Body
{
"message": "Hello World"
}
+ Response 200 (application/json)
<ここに説明を書く>
+ Body
{
"message": "OK"
}
全体的な構造
1. Metadata section
2. API name & overview section
3. Resource group section
4. Resource section?Action section
5. Parameters section
6. Payload section
6.1. Request section
6.2. Response section
7. Data Structures section
Metadata section
Meta情報を記述
FORMAT: 1A
HOST: https://example.com
API name & overview section
APIの概要を記述
# Sample App
サンプルアプリです
Resource group section
グループの分割単位
Resource sectionの親section
ただし、Resource sectionは必須ではなくテキストだけでも良い
後述のAglioでのレンダリングでは、この単位でグルーピングされ
る
# Group コード値一覧
## 性別
|コード値 |名前|
|--------|----|
|Male |男性|
|Female |女性|
Resouce section?Action section
アクションを記述
親子関係はResouce section > Action sectionだが、実際にはどちらか
でURI templateを用いてHttp methodとPathを記述する必要があ
る。実質、この2つは一体的なものとして捉えるとよい
複数の書き方があるが、書き方は統一した方がよい
せめて2種類ぐらいには統一したい
Action sectionにはResponse sectionが必須
パターン1
## ユーザー一覧を取得する [GET /users{?offset,limit}]
<Parameters section>
<Response section>
## ユーザーを作成する [POST /users]
<Request section>
<Response section>
パターン2
## ユーザーの更新?削除 [/users/{userId}]
<Parameters section>
### ユーザーを更新する [PUT]
<Request section>
<Response section>
## ユーザーを削除する [DELETE]
<Response section>
URI template
URIを記述、パラメータはRFC6570準拠
path
/users/{userId}
query
/users{?offset,limit}
fragment
/users{#var}
Parameters section
MSONで指定
path
+ Parameters
+ userId: 1 (number, required) - ユーザーID
query
+ Parameters
+ offset: 0 (number, optional) - オフセット
+ limit: 10 (number, optional) - リミット
Payload section
HTTPのリクエストやレスポンスについて記述
以下のsectionを含む
Header section
Body section
Schema section
Attributes section
Request?Response sectionはこれを継承している
Media Typeを指定できる
Request section
Requestに関する情報を記述
+ Request (application/json)
+ Attributes
+ firstName: Naoki (string, required) - 名
+ lastName: Gondo (string, required) - 姓
Response section
Requestに関する情報を記述
Media Typeやステータスコードごとに分けられる
+ Response 200 (application/json)
+ Attributes (User)
+ Response 400
Body?Schema?Attributes sectionの使い分け
Attributes sectionにMSONで書くのがオススメ
後述のAglioを使用する際も、Attributes sectionのほうが便利
Schemaの定義は後でいい、という場合はBody sectionだけというの
もあり
後述のDrakovでMockサーバーを使うときなど
Schema sectionを用いることはあまりないと思う
強いていえば、MSONで定義できないJSON Schema( maxLength な
ど)を使いたい場合ぐらい
Attributes sectionとの相性が悪いので、Body sectionとのセット
で使うのを推奨
Multiple Request/Response
複数記述できる
RequestのパターンによってResponseが微妙に違うようなケースに
有効
+ Request A
+ Response 200 (application/xml)
+ Response 200 (application/json)
+ Request B
+ Response 200
+ Response 400
+ Request C
+ Request D
+ Response 200
Data Structures section
sectionに名前を定義して参照できる
基本的にはAttributes sectionで用いるもの(Model)を書く
Modelの定義の例
# Data Structures
# User (object) - ユーザー
+ id: 1 (number, required) - ユーザーID
+ firstName: Naoki (string, required) - 名
+ lastName: Gondo (string, required) - 姓
+ gender (Gender, required) - 性別
+ birthday (object, optional) - 生年月日
+ year: 1988 (number, required) - 西暦年
+ month: 2 (number, required) - 月
+ day: 18 (number, required) - 日
Data Structures section
Enumの定義
# Gender (enum, fixed) - 性別
## Members
+ Male - 男性
+ Female - 女性
Data Structures section
Data Structuresで定義したものを使う
+ Response 200 (application/json)
+ Attributes
+ total: 3 (number, required) - 全件数
+ list (array[User], required, fixed-type) - ユーザー一覧
MSONについて
Markdown Syntax Object Notation
(https://apiblueprint.org/documentation/mson/speci cation.html)
型を定義するための記述方法。JSON Schemaをシンプルにしたよう
なもの
一般的に使うには、覚えることはそこまで多くない
(凝った書きかたをする場合はこの限りではない)
JSON Schemaと比べると機能が少ないためシンプル
その分、細かなvalidationルールは書けない
Example
ユーザー一覧を取得するAPIのレスポンス
+ Attributes
+ total: 3 (number, required) - 全件数
+ list (array, required, fixed-type) - ユーザー一覧
+ (object)
+ id: 1 (number, required) - ユーザーID
+ firstName: Naoki (string, required) - 名
+ lastName: Gondo (string, required) - 姓
+ gender (Gender, required) - 性別
+ birthday (object, optional) - 生年月日
+ year: 1988 (number, required) - 西暦年
+ month: 2 (number, required) - 月
+ day: 18 (number, required) - 日
書式
基本的には以下のように書く
+ プロパティ名: サンプル値 (型属性1, 型属性2) - 説明
プロパティ名は必須
サンプル値?説明は省略可
型属性は複数指定可
型属性は省略可能だが、必ず書くことを推奨
省略時は(string, required) が適用される
階層構造(型属性: object)の場合はインデントでネストさせる
型属性
string
number
boolean
object
array
enum
その他の属性
required
optional
nullable
その他の機能
Type Inheritance
Mixin Type
Generic Named Type
詳しくはドキュメントで
4. Api Blueprintを支えるツール
Api Blueprintを支えるツールたち
一覧: (https://apiblueprint.org/tools.html)
今回紹介するものは以下の3つ
1. Renderers (Aglio)
2. Testing (Dredd)
3. Mock serevers (Drakov)
このスライドの冒頭に記載しているサンプルコードにもありますの
で、実際に手元で動かしてみてください
4.1 Aglio
HTMLレンダリングツール(https://github.com/danielgtaylor/aglio)
複数のThemeを提供
ライブリロード機能
ファイル分割
Quick start
HTMLへの出力
$ npm install -g aglio
$ aglio -i input.md -o output.html
ライブリロード
$ aglio -i input.md -s -p 3001
http://localhost:3001 で編集しながら確認
文法がおかしい場合はコンソールにエラーが出る
ファイル分割とコンパイル
examples/
├── base.md
├── endpoints
│?? └── users.md
├── meta
│?? └── common.md
└── models
└── models.md
endpoints/users.md にはGroup Sectionを記述
meta/common.md にはMetadata Sectionを記述
models/models.md にはData Structuresを記述
ファイル分割とコンパイル
examples/base.mdの内容
FORMAT: 1A
# Sample App
<!-- include(meta/common.md) -->
<!-- include(endpoints/users.md) -->
<!-- include(models/models.md) -->
コンパイル
$ aglio -i examples/base.md -c -o output.md
Aglioについての所感
Attribute sectionを書けばJSON Schemaをレンダリングしてくれる
のが非常に便利
元々のMarkdownもHTMLにしてくれるので、表や内部リンクも使え
る
ファイルの分割機能が便利
この機能を知るまでは自前のシェルスクリプトで頑張って結合し
ていた
Aglioについての所感
Attributes sectionを書くとBody sectionで書いた内容が反映されな
い
ActionごとのExample valueを指定できない
かといってBody sectionとSchema sectionを両方書く気にはなら
ない
しかしこのあたりはswaggerも一緒なので妥協しています
Attributes sectionをもとにJSON Schemaをレンダリングする挙動が
少しおかしい時がある
JSON Schemaが壊れるほどではないので、許容範囲
4.2 Dredd
テスティングツール(https://github.com/apiaryio/dredd)
ドキュメント(https://dredd.readthedocs.io/en/latest)
実際に動いているAPIサーバーに対してリクエストを行い、レスポン
スの内容をテストすることができる
デフォルトではResponse sectionでの定義(ステータスコード、
Header?Body)のチェックを行う
BodyについてはJSON SchemaでのValidationを行う
hook処理を用いることで細かな制御やテストも可能
実はSwagger Specも実行できる(少し制限があるが)
Quick start
$ npm install -g dredd
$ dredd init
$ dredd
※ dredd init で設定する項目は公式ドキュメントを参照
テストの成功例
リクエストの実行順は、デフォルトではSpeci cationで上から書いた順
番に行われる(設定ファイルで変更可能)。
> ./node_modules/dredd/bin/dredd
info: Configuration './dredd.yml' found, ignoring other arguments.
info: Beginning Dredd testing...
pass: GET /users?offset=0&limit=10 duration: 47ms
pass: POST /users duration: 27ms
pass: PUT /users/1 duration: 18ms
pass: DELETE /users/1 duration: 6ms
complete: 4 passing, 0 failing, 0 errors, 0 skipped, 4 total
complete: Tests took 106ms
テストの失敗例
下記の例(一部抜粋)では「 list[0].id とlist[1].id の型が、仕様書では
string だけどnumber になってるよ」と言っている
> ./node_modules/dredd/bin/dredd
info: Configuration './dredd.yml' found, ignoring other arguments.
info: Beginning Dredd testing...
fail: GET /users?offset=0&limit=10 duration: 56ms
pass: POST /users duration: 17ms
pass: PUT /users/1 duration: 18ms
pass: DELETE /users/1 duration: 9ms
info: Displaying failed tests...
fail: GET /users?offset=0&limit=10 duration: 56ms
fail: body: At '/list/0/id' Invalid type: number (expected string)
body: At '/list/1/id' Invalid type: number (expected string)
設定ファイル(dredd.yaml)
起動オプションでも同じような指定ができる
blueprint : Api Blueprint Speci cationファイルの指定
endpoint : テストするAPIのhostの指定
hookfiles : hookファイルの指定
header : 全てのRequestに付与するHeader情報を指定
only : テストするtransactionの指定
method : テストするHTTPメソッドの指定
level : ログレベル
hookについて
複数の言語で書ける(Go, Node.js, Perl, PHP, Python, Ruby)
前処理?後処理が書ける
Requestをカスタマイズできる
デフォルトではExample ValueやDefault Valueが使われるため
Responseに対してCustom Validationが書ける
詳しくはドキュメントやExample
(https://github.com/apiaryio/dredd-example) を参照
hook例(前処理?後処理)
var hooks = require('hooks');
hooks.beforeAll(function(transaction) {
// テスト全体での前処理
});
hooks.beforeEach(function(transaction) {
// transation毎の前処理
});
hooks.afterAll(function(transaction) {
// テスト全体での後処理
});
hook例(指定したtransactionの前処理)
hooks.before('Transaction Name', function(transaction) {
// Requestの書き換え
var url = transaction.fullPath;
transaction.fullPath = url.replace('1', '12345');
});
hook例(テストのスキップ)
hooks.before('Transaction Name', function(transaction) {
transaction.skip = true;
});
hook例(Custom validation)
var assert = require('assert');
hooks.after('Transaction Name', function(transaction) {
// JSONの完全一致チェック
var expected = JSON.parse(transaction.expected.body);
var actual = JSON.parse(transaction.real.body);
assert.deepEqual(expected, actual);
});
Transaction Name
Resouce section?Action sectionの書き方によって決まる
サンプルの例だと、'ユーザー > ユーザー一覧を取得する> ユーザー
一覧を取得する'となる
パターンが多いので、よくわからない時はログを仕込んで調べてみ
てください
hooks.beforeEach(function(transaction) {
console.log(transaction.name);
});
Transaction Object
hookスクリプトで引数に受け取る関数の引数
「speci cationをもとに生成された、HTTPリクエスト?レスポンス
に必要なものが揃っている」という認識でOKです
詳しくはドキュメントで
(https://dredd.readthedocs.io/en/latest/data-structures/)
Dreddについての所感
デフォルトでスキーマのテストができるのが便利
hookを組み合わせれば細かなチェックやパターン網羅もできる
Dreddについての所感
hookでできることを知らないと少々大変
e2eテストのレベルのことをやるべきではない
ステートレスなものだけやるのは楽(HTTPでいうとGETメソッド
だけ、とか)
ステートフルなものはDBの初期化などがどうしても必要になる
その仕組みを作るのに時間をかけるのであれば、skipするとい
うのもひとつの手
目的に応じて、ユニットテストやその他のe2eテストをやりましょ
う
4.3 Drakov
モックサーバー (https://github.com/Aconex/drakov)
Quick start
$ npm install -g drakov
$ drakov -f example1.md
$ curl -XGET http://localhost:3000/users
Drakovについての所感
APIを作る側と使う側が並行してアプリケーションを開発する場合に
役に立つ
結合テストの前にローカル環境で動作を確認できる
watch機能があるのでMockサーバーを立ち上げたままでも編集しな
がら確認ができる
汎用的にMockサーバーとして使いたい場合は、Body sectionをきち
んと書く必要がある
Attributes sectionだけ書いた場合はExample Valueを用いてレス
ポンスが作られるので、ニーズに合わないことがある
arrayのサイズが1固定になってしまう、など
ツールの裏側について(開発者向け)
Api Blueprint用の独自ツールを作りたい場合は参考にすると良いです
1. drafterでApi Blueprintをパースし、Api Elementsに変換
drafter (https://github.com/apiaryio/drafter)
Api Elements (http://api-elements.readthedocs.io/en/latest/)
2. 各種ツールはこのApi Elementsをもとに処理
Dreddの場合、さらにdredd-transactionsでHttp Transactionに変
換(https://github.com/apiaryio/dredd-transactions)
Apiaryサービスについて
この他、Apiaryが提供するサービスもあるhttps://apiary.io/
Githubとの連携
Apiary Editor
テスティングレポート
無償で使えるのはpublic repositoryのみ
他にもいろいろなツールがあるので、試してみ
てください
Converters (https://apiblueprint.org/tools.html#converters)
Api Blueprint speci cationからコードを自動生成するツール
5. プロジェクトに導入した話
新規API作成案件
1. アプリケーションの内部はブラックボックスとし、
Request/Responseだけ先に定義
2. APIの注意点も書いておく
RequestのValidation
Responseのリストの並び順
3. 仕様書をもとに設計ミーティングで擦り合わせ
4. 実装中に変更点があったらドキュメントも修正してすぐに通知
既存のAPI作り替え案件
1. ドキュメントはCon uenceでまとめていたが、所どころ乖離が見ら
れたので、Aglioできちんとまとめることにした
同じgithub repositoryで管理したいというのもあった
2. 表と内部リンクを組み合わせる箇所が多かった
3. Multiple Request/Responseが役に立った
Requestのパターンが多く、それに対応したResponseを定義して
Dreddでテストした
既存のAPI案件(1)
(現在進行中)APIドキュメント作成中
リリース優先で作り込みをやってきたのでAPIドキュメントが整備
しきれていない
Request?Responseのパターンが多く漏れがある
optionalな項目が多いとDreddのテストでも気付けないので見落と
しがち
ステートを持つものは基本的にテストをskipさせている
Dockerでのクリーンな環境構築も考え中
既存のAPI案件(2)
Aglioだけ用いている
Dreddは用いていないが、ユニットテストをしっかり行っている
Restfulな設計になっている
ルールが徹底しているのでドキュメントの更新漏れがない
I/Fに変更がある場合は、同じPull Requestで修正する
所感
APIドキュメントを使った開発フローを徹底するのはどうだろうか
Request/ResponseのModelはドキュメントから自動生成する
APIのI/Fが変わる時は先にドキュメントを更新することになる
Modelのpackageや継承関係もはっきりさせておく
RequestのValidationルールを明記する
まとめ
まとめ
Api Blueprintを使うと手軽にAPIドキュメントが作れる
ベースはMarkdownなので、自由に書きやすい
MSONは少し複雑だが、主に使うものは決まっているのでそこだ
け覚えればOK
HTMLでのドキュメント出力ができる
HTTPリクエスト?レスポンスのテストができる
Dreddは高機能だがハマることもあるので、チームで話し合って
決めてください
モックサーバーを用いての開発ができる
Swagger Speci cationとの比較
SwaggerはJSON Schemaに準拠しているだけあって、厳格に書ける
より開発者向け
Api Blueprintは仕様について任意の箇所でテキスト(Markdown)で記
述しやすい
開発者や勿論、ディレクター向けの仕様書としても書きやすい
ドキュメントが先かソースコードが先か
APIドキュメントをきちんと書いた上で、開発を進めるのがよいと思
います
個人的な意見としては
APIドキュメントは「仕様」である
ソースコードが示すのは「挙動」であり「仕様」ではない
APIドキュメントに限らず、ドキュメントはきちんと書きましょう
どこかでツケを払う時期が来ます...
参考にさせていただいた資料
aglioとdrakovでAPI仕様書とMockを生成する手順
(http://takemikami.com/2017/01/05/agliodrakovAPIMock.html)
すごーい!APIドキュメントを更新するだけでAPIが自動テストでき
ちゃう!たのしー!
/dcubeio/api-blueprint-75780293
ご静聴ありがとうございました

More Related Content

Apiト?キュメンテーションツールを使いこなす【api blueprint編】