api blueprintとdrakovを利用してAPIモックサーバを立ち上げる

## 概要

Web APIの開発をするのにapi blueprintとdrakovを利用するとモックサーバを簡単に立ち上げられると聞いて試してみました。

api blueprint
https://apiblueprint.org/

こちらの記事を参考にさせてもらいました。感謝！

API BlueprintとdrakovとdreddでAPIドキュメントを書きつつモックサーバを立ててさらにテストを走らせる
https://arata.hatenadiary.com/entry/2018/03/22/204723


今回構築した環境をGitHubにUPしていますので、ご参考ください。
https://github.com/kai-kou/api-blueprint-use-drakov


## 環境構築

いつもDockerを利用しているので、Docker環境を用意します。
こちらは趣味なので、ローカルでもOKです。
node.jsが利用できるようにイメージを指定します。

```sh
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> touch Dockerfile
> touch docker-compose.yml
```

```txt:Dockerfile
FROM node:latest

WORKDIR /projects
```

```yaml:docker-compose.yml
version: '3'

services:
  api:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ".:/projects"
    tty: true
```

```sh
> docker-compose up -d
> docker-compose exec api bash
```

## API定義を用意する

api blueprintの仕様でmdファイルを作成します。

```sh
> mkdir md
> touch md/sample.md
```

```md:md/sample.md
# GET /message
+ Response 200 (text/plain)

        Hello World!
```


## モックサーバを立ち上げる

環境が準備できたらdrakovをインストールします。

```sh:コンテナ内
> npm install -g drakov
```

インストールできたか確認します。

```sh:コンテナ内
> drakov
[INFO] No configuration files found
[INFO] Loading configuration from CLI
Usage:
  ./drakov -f <path to blueprint> [-p <server port|3000>]

Example:
  ./drakov -f ./*.md -p 3000
(略)
```

それでは、モックサーバを起動します。Dockerコンテナ内で実行する場合、```--public``` オプションを付けないとコンテナ外からアクセスできないのでご注意ください。

```sh:コンテナ内
> drakov -f md/sample.md --public

[INFO] No configuration files found
[INFO] Loading configuration from CLI
   DRAKOV STARTED
[LOG] Setup Route: GET /message
   Drakov 1.0.4      Listening on port 3000
   PUBLIC MODE      running publicly
```

アクセスしてみます。

```sh
> curl -v http://localhost:3000/message
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET /message HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Drakov API Server
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
< Content-Type: text/plain; charset=utf-8
< Content-Length: 13
< ETag: W/"d-oLZZOWcLwsAQ9NXWoLPk5FkPuSs"
< Date: Fri, 31 Aug 2018 09:07:01 GMT
< Connection: keep-alive
<
Hello World!
```
はい。

テキストを返しているだけだとつまらないので、JSONを返すようにしてみます。

```md:md/sample.md
# GET /message
+ Response 200 (application/json)

        [
          {
            "id": "1",
            "hoge": "ほげ",
            "fuga": "ふが"
          }
        ]
```

```sh
> curl -v http://localhost:3000/message
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET /message HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Drakov API Server
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
< Content-Type: text/plain; charset=utf-8
< Content-Length: 13
< ETag: W/"d-oLZZOWcLwsAQ9NXWoLPk5FkPuSs"
< Date: Fri, 31 Aug 2018 09:08:46 GMT
< Connection: keep-alive
<
Hello World!
```

変わらないですね。```--watch``` オプションを付けて立ち上げないとだめみたいです。

```sh:コンテナ内
> drakov -f md/sample.md --public --watch
[INFO] No configuration files found
[INFO] Loading configuration from CLI
   DRAKOV STARTED
[LOG] Setup Route: GET /message
   Drakov 1.0.4      Listening on port 3000
   PUBLIC MODE      running publicly
```

この状態で、mdファイルを保存すると。。。

```sh
[CHANGE] md/sample.md Restarting 1
   DRAKOV STOPPED
   DRAKOV STARTED
[LOG] Setup Route: GET /message
   Drakov 1.0.4      Listening on port 3000
   PUBLIC MODE      running publicly
```

反応してくれました^^

改めてアクセスしてみます。

```sh
> curl -v http://localhost:3000/message
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET /message HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Drakov API Server
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
< Content-Type: application/json; charset=utf-8
< Content-Length: 70
< ETag: W/"46-YVQUXYNINs/mq4ldrdja8KnDu00"
< Date: Fri, 31 Aug 2018 09:13:09 GMT
< Connection: keep-alive
<
[
  {
    "id": "1",
    "hoge": "ほげ",
    "fuga": "ふが"
  }
]
```

やったぜ。


最後に複数mdファイルがあったらどうなるか見ておきます。

```sh
> cp md/sample.md md/sample2.md
> vi md/sample2.md
```

```md:md/sample2.md
# GET /message2
+ Response 200 (application/json)

        [
          {
            "id": "1",
            "hoge": "ほげ",
            "fuga": "ふが"
          }
        ]
```

```sh:コンテナ内
> drakov -f "md/*.md" --public --watch

[INFO] No configuration files found
[INFO] Loading configuration from CLI
   DRAKOV STARTED
[LOG] Setup Route: GET /message
[LOG] Setup Route: GET /message2
   Drakov 1.0.4      Listening on port 3000
   PUBLIC MODE      running publicly
```

ちゃんと認識してくれました。けどなぜか```""``` で括らないと最初に見つけたファイルのみ読み込むという謎仕様でした^^

```sh:コンテナ内
> drakov -f md/*.md --public --watch

[INFO] No configuration files found
[INFO] Loading configuration from CLI
   DRAKOV STARTED
[LOG] Setup Route: GET /message
   Drakov 1.0.4      Listening on port 3000
   PUBLIC MODE      running publicly
```

それではapi blueprintを利用した、良きAPI開発ライフを^^


## 参考

api blueprint
https://apiblueprint.org/

API BlueprintとdrakovとdreddでAPIドキュメントを書きつつモックサーバを立ててさらにテストを走らせる
https://arata.hatenadiary.com/entry/2018/03/22/204723