【テンプレート配布】APIドキュメントとモックサーバを同時に生成する【API Blueprint】

この記事は [DeNA 21 新卒 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/dena-21-shinsotsu) の5日目の記事です。

## はじめに

クライアントサイドとサーバサイドで分かれて開発をする際、開発を円滑に進めるためにAPIドキュメントを作成することがあると思います。その際、仕様を記述したファイルをもとにモックサーバも立てられると楽だと思い、それを実現するテンプレートを作成してみました。

**テンプレート配布先(GitHub)**: https://github.com/konatsup/api-blueprint-example
(使い方は`README.md` にまとめてあります。)


## 今回作成したサンプル
テンプレートとなるExampleから2つ、実用的な例であるTodoアプリから3つの合計5つのエンドポイントを作成してみました。
<a href="https://docs-api-blueprint-konatsup.netlify.app">
![スクリーンショット 2020-11-28 15.25.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152658/7421f751-7458-1a57-20a6-3ba76a93534e.png)</a>


ドキュメント: https://docs-api-blueprint-konatsup.netlify.app
モックサーバ: http://mock-api-blueprint-konatsup.herokuapp.com

## そもそもAPIドキュメントとは？
**APIの仕様をまとめた文書**のことです。これを確認することで、どのような振る舞いをするAPIなのかをすぐに把握できます。
例えば、[GitHub REST API](https://docs.github.com/en/free-pro-team@latest/rest) の指定したユーザ情報を取得するAPIは以下のようになっています。*(スクショ撮影日: 2020-11-28)*

![スクリーンショット 2020-11-28 13.35.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152658/eb45fe51-8840-720f-b88c-6d2b14dd3e72.png)

参考: [Users - GitHub Docs#get-a-user](https://docs.github.com/en/free-pro-team@latest/rest/reference/users#get-a-user)

ここでは

- Title
- Description
- HTTP Request Method
- Endpoint
- Parameters
- Default Response

などが記載されています。

このようなAPIドキュメントを作成することで、APIの仕様確認などクライアントチームとサーバチームの無駄なコミュニケーションを減らすことができ、より円滑に開発を進めることができます。他にも、新しくサーバチームにjoinしたメンバーが全体の仕様を把握するのに役立つので、サーバサイドの開発スピードが上がるなどのメリットがあります。

デメリットとしては、ドキュメントの保守コストがかかることがあげられます。ドキュメントを書く場合、本番APIとドキュメントの仕様が一致するように随時更新していく必要があります。そのため、機能が少ないプロダクトや長期的に保守する必要がないプロダクトであれば、ドキュメントを作らない選択もありだと思います。

## モックサーバとは？
APIのモックアップとして**ダミーデータを返してくれるサーバ**です。これがあることでサーバ側のAPI実装が間に合っていなくてもクライアント側の開発を並列的に進めることができます。また、リリース前はモックサーバを使って実装し、リリースする際に本番サーバに繋いでテストすることも可能なので、モックサーバがあれば(基本的に)クライアント側の開発は全て進められるようになります。

![mockserver.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152658/0f4aa9cf-49e3-5b32-13cf-41d2dc5d8cdd.jpeg)


## API Blueprintとは？
**APIの仕様をMarkdown拡張記法で記述できる言語**です。**一番の特徴はほぼMarkdownのような書き方で記述できるため、記法の学習コストが比較的低いこと**だと思います。ささっと仕様書を作る、拡張するのであれば最適だと思います。

※ 同じような目的でよく[Swagger](https://swagger.io/) が使われますが、今回導入を検討したチームではSwagger経験者がおらず記法に慣れるまで時間がかかりそうだったため、スピード重視でAPI Blueprintを採用しました。

また、同じAPI Blueprintのファイルからドキュメントやモックサーバを生成してくれる便利なパッケージ(後述)があり、さくっと作ることができました。

参考: [API Blueprint - A powerful high-level API description language for web APIs -](https://apiblueprint.org/) 


**では実際に作っていきましょう！**


## 作成手順
1. Node.jsのインストール
2. 各種packageのインストール
3. .apibファイルを編集する
4. ドキュメントの生成・更新
4. モックサーバを立てる

### 1. Node.jsのインストール

Node.jsがインストールされているか確認します。バージョンが表示されていればOKです。

```
$ node -v
v15.2.0
```

**Node.jsのインストール方法** ([参考記事](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09))

```
$ brew install nodebrew
$ mkdir -p ~/.nodebrew/src
$ nodebrew install-binary stable
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc    //コメント: bash使ってるなら >> ~/.bashrc とかで
$ source ~/.zshrc
$ node -v
```

### 2. 各種packageのインストール
以下の2つのpackageを使用します。

- [aglio](https://github.com/danielgtaylor/aglio) (ドキュメント(HTML)生成)
- [dracov](https://github.com/Aconex/drakov) (モックサーバ作成)

```shell
$ npm install -g aglio --unsafe-perm
$ npm install -g drakov@1.0.4 
```

※ 注意: drakovの最新バージョンは現在`v2.0.1`ですが、デプロイ時に不具合が発生したため`v1.0.4`にしています。


### 3. ドキュメント(.apib)を編集する
API Blueprintのファイル拡張子は`.apib`です。まずファイルを作成し中身を編集していきます。
今回はテンプレートにあるものではなく、最低限必要なものだけを記載します。(このファイルを見ただけでもどんな仕様かがわかりやすいと思います。)

```apib:input.apib
FORMAT: 1A
HOST: http://localhost:3000

## Example [/example]
### Example GET API [GET]
#### 処理概要

* [端的にどんなAPIかを書く]
* [注意点、特記事項など]

+ Response 200 (application/json)
  + Attributes
      + value: `GET API Response Example` (string) - 値

### Example POST API [POST]
#### 処理概要

* [端的にどんなAPIかを書く]
* [注意点、特記事項など]    

+ Request (application/json)
  + Attributes
      + value: `POST API Request Example` (string, required) - 値

+ Response 200 (application/json)
  + Attributes
      + value: `POST API Response Example` (string) - 値
```


API Blueprintの文法については以下の記事が参考になりました。

- [API Blueprint Tutorial](https://github.com/apiaryio/api-blueprint/blob/master/Tutorial.md)
- [API Blueprint の書き方](https://tex2e.github.io/blog/misc/api-blueprint)

※ ちなみに、VSCodeの場合は以下のプラグインが便利です。

- [API Elements extension](https://marketplace.visualstudio.com/items?itemName=vncz.vscode-apielements) (syntax highlightがつく)
- [API Blueprint Viewer](https://marketplace.visualstudio.com/items?itemName=develiteio.api-blueprint-viewer) (Live previewができる)

### 4. ドキュメントの生成・更新
aglioを使って、`input.apib` からHTMLファイル(`index.html`)を生成します。

```
$ aglio --theme-variables flatly -i input.apib -o index.html
```

`--theme-variables` を使うことで色などのスタイルを指定することができます。`flatly`の他にも `cyborg`や`slate`があります。

参考: [danielgtaylor/aglio#custom-colors-style](https://github.com/danielgtaylor/aglio#custom-colors--style)

`index.html`を開くとこのようになります。`Show` ボタンを押すことで具体的な仕様を確認できます。
![スクリーンショット 2020-11-28 17.25.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152658/08ae0b66-20fc-fc3a-994a-4a0f48a12cd6.png)


### 5. モックサーバを立てる
drakovを使ってモックサーバを立てます。

```shell
$ drakov -f input.apib --public -p 3000
```

試しに、`curl`を使って`http://localhost:3000/example`にGETとPOSTリクエストを送ってみましょう。

```shell

$ curl -X GET http://localhost:3000/example
{
  "value": "GET API Response Example"
}
```

```shell
$ curl -X POST http://localhost:3000/example -H 'Content-Type:application/json' -d '{"value":"hoge"}'
{
  "value": "POST API Response Example"
}

```

ちゃんとAPIドキュメントの仕様どおりの値が返っていることがわかります。
これで完成となります。

## (おまけ) Herokuにモックサーバをデプロイ
今回作成したモックサーバを試しにHerokuにデプロイしてみます。(参考: [Container Registry & Runtime (Docker Deploys)](https://devcenter.heroku.com/articles/container-registry-and-runtime))

まず、`Dockerfile`を作成します。

```dockerfile:Dockerfile
FROM node:14-alpine3.11

WORKDIR /projects

COPY . /projects

RUN npm install -g drakov@1.0.4

ENV PORT=${PORT}

CMD ["drakov","-f", "input.apib", "--public", "-p", "$PORT"]
```

次に、`heroku.yml`を作成し、Heroku上でDockerコンテナを動かすための設定を記述します。

```yml:heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: drakov -f input.apib --public -p $PORT
```

最後に、以下のコマンドを打つことでデプロイします。

```shell
$ heroku login
$ heroku create アプリ名
$ heroku container:login
$ heroku stack:set container
$ git push heroku main
```

これで完了です。


## 終わりに
APIドキュメントとモックサーバがあることでクライアント側が独立して開発でき、圧倒的に開発効率を上げることができます。まだ使ってみたことがない方はぜひ導入してみてください！

## 宣伝
この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ Twitter や facebook、はてなブックマークにてコメントをお願いします！
また [DeNA 公式 Twitter アカウント @DeNAxTech](https://twitter.com/DeNAxTech) では、 Blog記事だけでなく色々な勉強会での登壇資料も発信してます。ぜひフォローして下さい！→ <a href="https://twitter.com/intent/follow?screen_name=DeNAxTech">Follow @DeNAxTech</a>