SwaggerでAPIを定義してインタラクティブAPIドキュメントを見る

[Swagger](http://swagger.io/getting-started/)を使ってAPI定義をしてスタブを動かしてみます。
Swaggerの関連ツールは様々な言語に対応していますが、ここではNode.jsを使って試してみます。

## Swaggerとはなんぞ？

Swaggerは関連ツールが多くあるので全容がつかみにくいのですが、

> What is Swagger?
The goal of Swagger™ is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. 

端的に言うと「REST API仕様を定義するもの」ということです。
API定義言語と言ってもよいでしょう。

この分野はSwaggerを含め、

* [apiblueprint](https://apiblueprint.org/)
* [RAML](http://raml.org/)

の三大勢力が有力なようですが、次の理由でSwaggerを選択しました。

* JSONだけど、YAMLで書けば書きやすい
* [swagger-codegen](http://swagger.io/swagger-codegen/)で色々な言語のscaffoldが吐き出せる
* AWS API Gatewayに反映できる(aws console, awscliでインポートできるようになりました）
    * https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/create-api-using-import-export-api.html
    * `aws apigateway put-rest-api --rest-api-id xxxxxxx --body file:///home/newgyu/swagger.yaml --mode overwrite`

## Swaggerを使ってみる

Swaggerにはいろいろな周辺ツールがあり逆に悩ましいのですが、ここでは

1. [オンライン版のswagger-editor](http://editor.swagger.io) を使ってswagger.yamlを書く
2. swagger-editorからNode.jsのscaffoldコードを吐き出してそれを利用する

この利用法を採用しました。
 
### API仕様を書く

Swaggerの記法は[swagger-specification](http://swagger.io/specification/)に書かれている通りJSONです。しかし、Jsonは各キーに`""`をつけたり、`{}`で囲う必要があったりして書くのが割とめんどくさいので一般的にはYAMLで書くようです。（YAMLはJSONへの変換が簡単に行えます）

YAMLを書けばいいので道具はテキストエディターなら何でも良いのですが、[swagger-editor](http://swagger.io/swagger-editor/)というものが用意されています。swagger-editorはnode.jsで書かれたプログラムで

```shell-session
$ git clone https://github.com/swagger-api/swagger-editor.git
$ cd swagger-editor
$ npm start
```

これで動かすことが出来ますが、特に理由がなければオンライン版の http://editor.swagger.io を利用するのが手っ取り早いでしょう。

### HTML版のAPIドキュメントを見る

Swaggerの真骨頂は http://petstore.swagger.io/ のようなインタラクティブなAPI仕様のドキュメントを運用できることです。

[swagger-ui](http://swagger.io/swagger-ui/)というツールがJSONを食ってこのAPI画面をレンダリングをするのですが、swagger-uiの実体は [swagger-ui.js](http://petstore.swagger.io/swagger-ui.js) というJavaScript(Node.jsではなくブラウザで動くJS)ライブラリです。
つまり、ApacheなどのWEBサーバーに静的HTML+JSを書くだけで運用できます。(JSONをswagger-uiに渡すのはajaxでJSONをHTTP取得して渡す形です）

このように、静的HTMLの方法でもできるのですが、関連するCSSの配置やHTMLタグコーディングが面倒なので、最も簡単な「swagger-editorのGenerate Server機能を使う」方法を紹介します。

#### 1. swagger-editorからGenerate Serverする

![Screenshot from 2016-01-17 19:53:26.png](https://qiita-image-store.s3.amazonaws.com/0/31010/279d596f-c1a3-61a6-6b92-c8cfa15528e1.png)

ここでは`Node.js`を選択します。
すると、zipで固められたNode.jsのプロジェクト形式でダウンロードされます。

#### 2. 展開して実行

下記のコマンドで8080ポートでHTTPサーバーが起動します。

```shell-session
$ npm install
$ node index.js
```

http://localhost:8080/docs にアクセスするとAPIドキュメントが見えます。

### モック（スタブ）サーバーとして使う

```shell-session:node-serverのディレクトリ構造
.
├── README.md
├── api
│   └── swagger.yaml    #API仕様。書き換えて再起動すれば反映される。 
├── controllers         #codegenが吐いたScaffoldコード
│   ├── Default.js
│   └── DefaultService.js
├── index.js            #起動用のJS
└── package.json
```

index.jsに下記のような記述があり、環境変数`NODE_ENV`に`development`をセットするとスタブが使用できます。

```js:index.js
// swaggerRouter configuration
var options = {
  swaggerUi: '/swagger.json',
  controllers: './controllers',
  useStubs: process.env.NODE_ENV === 'development' ? true : true // Conditionally turn on stubs (mock mode)
};
```

APIドキュメントから`Try it out!`ボタンを押してみましょう。

![Screenshot from 2016-01-17 20:11:10.png](https://qiita-image-store.s3.amazonaws.com/0/31010/d3912f56-8e01-ef77-cb7e-5426632b9ba3.png)

AJAXでサーバーにリクエストが送られ、レスポンス内容が画面に表示されます。
直接``curl -X GET --header "Accept: application/json" "http://localhost:8080/v1/pets/11111"``しても結果が得られるはずです。

注意点としては、userStbsの意味するところはswagger-codegenが吐き出したcontrollersを使ってレスポンスを返しているわけでなく、[swagger-router](https://github.com/apigee-127/swagger-tools/blob/master/docs/Middleware.md#swagger-router)というのが内部でゴニョゴニョした固定値が帰ってくるようになっていました。（String型なら"Sample text"とか）
このへんの話はまた次回にします。

なお、Swaggerには[レスポンスJSON例を定義するセクション](http://swagger.io/specification/#responseObject)があるのですが、残念ながら上記のuseStubでは考慮してくれないようです。（swagger-toolのバージョンアップに期待)

次回はswagger-codegenで吐き出されたコードの掘り下げと、それをexpressで動かすことをしてみたいと思います。