API Mockサーバ(node-easymock) の DockerImage を作ってみた

# はじめに

Webアプリケーションをプロジェクトとして作成する際に、Front側チームとBackend側チームに分ける場合があります。
具体的に記載すると、Frontend側は、ブラウザで表示を行う html, css, javascript などを担当し、Backend側は、データの入出力などを行うAPI Serverを担当します。

Frontend側とBackend側を、効率よく並列で作業を進めるために、開発初期の段階で仮のAPI を実行する API Mockserverを構築することが多いと思います。

API MockserverをDockerで配布出来るようにしたため、手順を共有します。



# DockerImage作成側：node-easymockのDockerImage作成

API Mockserverを提供するOSSは様々なものがありますが、今回はCyberAgentのnode-easymockを使用します。
これを採用した理由は、APIのResponse JSONを自由に定義することが出来るためです。



DockerFile作成

2018/9月の時点で nodeの最新tag 10.10.0 では、easymockをinstallすることが出来なったため、「node:5-slim」を使用しています。

WORKDIRとVOLUMEを /data としています。/data 配下に API ServerとしてResponseするjsonファイルを定義します。

```
mkdir ~/node-easymock
cd ~/node-easymock
cat <<'EOF' > ./Dockerfile
FROM node:5-slim
MAINTAINER sugimount <https://twitter.com/sugimount>

RUN npm install -g easymock@0.2.28

WORKDIR /data
VOLUME /data

EXPOSE 80
ENTRYPOINT ["node", "/usr/local/bin/easymock", "-p", "80", "-d", "/data"]
EOF
```



ImageBuild

```
docker build --tag=sugimount/qicoo-apimock:0.0.1 .
```



API の Responseのためのjson file作成

```
mkdir -p ~/node-easymock/api_responses/v1/questions/BosWT9EsdzgjPn
mkdir -p ~/node-easymock/api_responses/v1/users/IOodngp39890ba

# create a question
cat <<'EOF' > ~/node-easymock/api_responses/v1/questions_post.json
< @status 200
{
  "id": "BosWT9EsdzgjPn",
  "object": "question",
  "username": "sugimount",
  "event": "jkd1812",
  "program": "1",
  "comment": "kubernetesの〇〇について教えてください！",
  "created_at": "2018-09-08T09:07:09+09:00",
  "updated_at": "2018-09-08T09:07:09+09:00",
  "like": 0
}
EOF


# Retrieve a Question
cat <<'EOF' > ~/node-easymock/api_responses/v1/questions/BosWT9EsdzgjPn_get.json
{
  "id": "BosWT9EsdzgjPn",
  "object": "question",
  "username": "sugimount",
  "event": "jkd1812",
  "program": "1",
  "comment": "kubernetesの〇〇について教えてください！",
  "created_at": "2018-09-08T09:07:09+09:00",
  "updated_at": "2018-09-08T09:07:09+09:00",
  "like": 0
}
EOF

# Delete a Question
cat <<'EOF' > ~/node-easymock/api_responses/v1/questions/BosWT9EsdzgjPn_delete.json
{
  "id": "BosWT9EsdzgjPn",
  "object": "question",
  "deleted": true
}
EOF

# get all questions
cat <<'EOF' > ~/node-easymock/api_responses/v1/questions_get.json
{
  "object": "list",
  "data": [
    {
      "id": "BosWT9EsdzgjPn",
      "object": "question",
      "username": "sugimount",
      "event": "jkd1812",
      "program": "1",
      "comment": "kubernetesの〇〇について教えてください！",
      "created_at": "2018-09-08T09:07:09+09:00",
      "updated_at": "2018-09-08T09:07:09+09:00",
      "like": 0
    },
    {
      "id": "IOdeamop2243v",
      "object": "question",
      "username": "hhiroshell",
      "event": "jkd1812",
      "program": "1",
      "comment": "世界を平和にする方法を教えてください！",
      "created_at": "2018-09-08T09:09:09+09:00",
      "updated_at": "2018-09-08T09:09:09+09:00",
      "like": 0
    }
  ]
}
EOF

# like a question
cat <<'EOF' > ~/node-easymock/api_responses/v1/questions/BosWT9EsdzgjPn/like_put.json
{
  "id": "BosWT9EsdzgjPn",
  "object": "question",
  "username": "sugimount",
  "event": "jkd1812",
  "program": "1",
  "comment": "kubernetesの〇〇について教えてください！",
  "created_at": "2018-09-08T09:07:09+09:00",
  "updated_at": "2018-09-08T09:07:09+09:00",
  "like": 1
}
EOF

# Create a User
cat <<'EOF' > ~/node-easymock/api_responses/v1/users_post.json
{
  "id": "IOodngp39890ba",
  "object": "user",
  "user_session": "hogehoge",  
  "username": "sugimount",
  "type": "twitter",
  "created_at": "2018-09-08T09:07:09+09:00",
  "updated_at": "2018-09-08T09:07:09+09:00",
  "user_url": "https://twitter.com/sugimount"
}
EOF

# Retrieve a User
cat <<'EOF' > ~/node-easymock/api_responses/v1/users/IOodngp39890ba_get.json
{
  "id": "IOodngp39890ba",
  "object": "user",
  "user_session": "hogehoge",  
  "username": "sugimount",
  "type": "twitter",
  "created_at": "2018-09-08T09:07:09+09:00",
  "updated_at": "2018-09-08T09:07:09+09:00",
  "user_url": "https://twitter.com/sugimount"
}
EOF

# Delete a User
cat <<'EOF' > ~/node-easymock/api_responses/v1/users/IOodngp39890ba_delete.json
{
  "id": "IOodngp39890ba",
  "object": "users",
  "deleted": true
}
EOF

# List all Users
cat <<'EOF' > ~/node-easymock/api_responses/v1/users_get.json
{
  "object": "list",
  "data": [
    {
      "id": "IOodngp39890ba",
      "object": "user",
      "user_session": "hogehoge",  
      "username": "sugimount",
      "type": "twitter",
      "created_at": "2018-09-08T09:07:09+09:00",
      "updated_at": "2018-09-08T09:07:09+09:00",
      "user_url": "https://twitter.com/sugimount"
    },
    {
      "id": "Gdi4235niopan",
      "object": "user",
      "user_session": "gugehuge",  
      "username": "hhiroshell",
      "type": "twitter",
      "created_at": "2018-09-08T09:08:09+09:00",
      "updated_at": "2018-09-08T09:08:09+09:00",
      "user_url": "https://twitter.com/hhiroshell"
    }
  ]
}
EOF
```



コンテナの起動

```
docker run --name apimock --rm -d -p 80:80 -v ~/node-easymock/api_responses/:/data/ sugimount/qicoo-apimock:0.0.1
```



curlで取得。jsonファイルの中味をそのままResponseしているので、各種パラメータはResponseの内容には何も反映されないことを注意してください。

```
# create a question
curl -s -v -H "Content-Type: application/json" -X POST http://localhost/v1/questions -d '
{
  "event": "jkd1812",
  "program": "1",
  "comment": "kubernetesの〇〇について教えてください！"
}
'

# Retrieve a Question
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/questions/BosWT9EsdzgjPn

# Delete a Question
curl -s -v -H "Content-Type: application/json" -X DELETE http://localhost/v1/questions/BosWT9EsdzgjPn

# list all questions
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/questions

# like a question
curl -s -v -H "Content-Type: application/json" -X PUT http://localhost/v1/questions/BosWT9EsdzgjPn/like

# create a user
curl -s -v -H "Content-Type: application/json" -X POST http://localhost/v1/users -d '
{
  "username": "sugimount",
  "type": "twitter",
  "user_url": "https://twitter.com/sugimount"
}
'

# Retrieve a user
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/users/IOodngp39890ba

# Delete a User
curl -s -v -H "Content-Type: application/json" -X DELETE http://localhost/v1/users/IOodngp39890ba

# List all Users
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/users
```



コンテナの停止

```
docker kill apimock
```



DockerHubへアップロード

```
docker login
docker push sugimount/qicoo-apimock:0.0.1
```





# 利用側：コンテナを起動して、API Mockを利用

sugimountのGitHubをcloneします。GitHub上には、SampleとしてJSONのResponseファイルが含まれているため、このまま利用することが出来ます

```
git clone https://github.com/Sugi275/qicoo-api-mock.git ~/qicoo-api-mock
docker run --name apimock --rm -d -p 80:80 -v ~/qicoo-api-mock/api_responses/:/data/ sugimount/qicoo-apimock:0.0.1
```





下記コマンドで、localhost宛にMock API を実行することが出来ます

```
# create a question
curl -s -v -H "Content-Type: application/json" -X POST http://localhost/v1/questions -d '
{
  "event": "jkd1812",
  "program": "1",
  "comment": "kubernetesの〇〇について教えてください！"
}
'

# Retrieve a Question
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/questions/BosWT9EsdzgjPn

# Delete a Question
curl -s -v -H "Content-Type: application/json" -X DELETE http://localhost/v1/questions/BosWT9EsdzgjPn

# list all questions
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/questions

# like a question
curl -s -v -H "Content-Type: application/json" -X PUT http://localhost/v1/questions/BosWT9EsdzgjPn/like

# create a user
curl -s -v -H "Content-Type: application/json" -X POST http://localhost/v1/users -d '
{
  "username": "sugimount",
  "type": "twitter",
  "user_url": "https://twitter.com/sugimount"
}
'

# Retrieve a user
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/users/IOodngp39890ba

# Delete a User
curl -s -v -H "Content-Type: application/json" -X DELETE http://localhost/v1/users/IOodngp39890ba

# List all Users
curl -s -v -H "Content-Type: application/json" -X GET http://localhost/v1/users
```