外部連携APIのMock API Server化を検討する (Mockoon)

# 0. 概要

ウェブサービスにおいての外部連携APIは、大きな生産性向上と新しい価値提供を成すようにしてくれますが、反面、制限された呼び出し環境と独自仕様の理由などで、インテグレーション開発中や開発後のテストや維持補修において、色々困難な経験があると思います。

この記事では、「どうやって外部連携APIをMock化し、ローカルでのテストと維持補修をしやすくするか？」を考えます。

流れとしては、以下のようになります。

1. Mockoonの紹介 (Mock API Server)
    ・ Mockoonの簡単な紹介と使い方を解説します
2. Mockoon TIP
    ・ もっと高度なMockAPI具現のために知っておけばいい内容を簡単に紹介します
3. Mockoonを利用したAPI明細のコード管理とDocker環境上での実行
    ・ どうやってMock API Server仕組みを、チーム開発に取り組み運用していくかを説明します
4. 外部連携APIのMock API Server化への考察
    ・ 必要性、期待効果、他のMock化に対するソリューションとその難点について説明します
5. Conclusion

> ※ Mock API Serverに関して既に経験があるか、ご存知の場合は、４から読んでいただいても良いと思います。
> ※ 実際の導入例ではありません。該当記事を元に、エンジニア組織内の導入を提案するための事前調査・資料も兼ねています。
> ※ あくまで個人主観が多く含まれているため参考までにご覧ください。


# 1. Mockoon紹介 (Mock API Server)

ここでは、Mockoonのインストールから簡単なテストまでの一連の過程を簡単に紹介します。
このパートの意図としては「どれだけ簡単にテスト目的のMock　APIを追加・拡張できるか」となります。

## 1-1. Mockoonとは

https://mockoon.com

Mockoonは、API Simulating Solution（Tool)の一つです。
Mock API Server Solutionの一つとも呼ばれます。

HTTPプロトコルベースのAPIを、簡単にモックアップレベルで作り、シミュレーションすることを可能にします。

## 1-2. インストール

macの場合、brewを利用して簡単にインストールできます。

```bash
brew install --cask mockoon
```

WindowsやLinux環境は、以下の公式サイトのインストールガイドをご参考ください。
https://mockoon.com/download/

## 1-3. ローカルサーバー起動

インストールすると、Mockoonを起動することができます。
最初に起動すると、Mockoonから基本提供されるDemoAPIを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/4153a638-5ffd-72b4-334a-050f10ac3c24.png)
ツールバーの左側にある「Start Server」アイコンを押すと、サーバーが起動し、DemoAPIとの疎通を試すことが可能になります。

## 1-4. 疎通テスト＆結果確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/69011847-0ce2-0fe6-15ba-12c1db271556.png)
画像のように、サーバーが起動中ということを確認できます。

DemoAPIのうち、`/users`APIと疎通を試します。
画面上の左のDemo APIのところに、`0.0.0.0:3000`を見ると、localhostのホスト名でポート3000でサーバーが起動されることがわかるので、`http://localhost:3000/users`のURLで疎通を試します。

```bash
❯ curl -v http://localhost:3000/users
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /users HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 4393
< Date: Mon, 21 Mar 2022 07:00:21 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
{
  "Templating example": "For more information about templating, click the blue 'i' above this editor",
  "users": [
      {
        "userId": "16861",
        "firstname": "Jerry",
        "lastname": "Simonis",
        "friends": [

# ...中略
```

また、Mockoon GUIでは、リクエストに対するログもまた確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/7b106d24-b9c3-99cd-d14d-1157fbcea37a.png)


こういう風に、DemoAPIの疎通結果が問題なく確認できます。
これで、Mockoonを利用して簡単にMockUp APIを追加しシミュレーションする準備が整いました。

## 1-5. カスタムEnvironment&API定義を追加

デモではなく、自ら新しいEnvironmentとAPIを追加するという一連の過程を通して、簡単にMockoonでのAPIの作り方と関連機能を説明します。

### 1-5-a. 新しいEnvironmentの作成

Environmentとは、Mockoon API Server環境の情報を統括管理する概念です。
一つのプロジェクトファイルと見ても特に問題はありません。

![mockoon1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/e5f857fb-fc46-7477-a64b-a52edb3f44fd.gif)

上記のように、new Environmentを使い、ファイル名をしていすると新しいEnvironmentが作成されます。
基本`/`パスで`{}`応答が設定されているので、サーバーを起動し疎通してみると、デモとは違う環境が簡単い作られたことを確認できます。

```
❯ curl http://localhost:3001
{}
```

### 1-5-b. API追加(パス、ヘッダ、ボディー設定)

`/hello`というパスのリクエストに対して、worldというtext/plain形式のレスポンスを返すAPIを追加してみます。

- メニューバーの「new route」をクリック
- 右のパス入力欄にをパスをhelloと指定
- ボディー入力欄にworldを入力
- Headersタブに入り、Content-Type: text/plainを指定

のように、すごく簡単にAPIを一つ追加しました。

![mockoon2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/20488ad7-c2ca-e57b-ea54-239dedd3caa9.gif)


### 1-5-c. 疎通テスト

`http://localhost:3001/hello`にリクエストすると、正常に応答されることを確認できます。


```bash
❯ curl -v http://localhost:3001/hello
# ...中略
< Content-Type: text/plain; charset=utf-8
< Content-Length: 5
# ...中略
world
```

# 2. Mockoon Tip


1.では、すごく簡単な動作確認とAPI追加をしてみました。これで、「どれだけMockoonは使いやすいか？」が伝わると思います。

ただし、APIの機能としては、シミュレーション目的だとしても、上記の機能だけだと限界があります。
なので、MockAPIを簡単かつ、より幅広い機能にするためのMockoonの機能を簡単に紹介します。

## 2-1. Routing

Mockoonは、routingに関する幾つかの機能を提供しています。

詳細は、こちらを参照できます。
https://mockoon.com/docs/latest/routing/

### 2-1-a. API route prefix

EnvironmentのAPI達のrouteに対して共通のprefixを指定できます。
Settings→API URL→prefix入力欄から設定できます。


### 2-1-b. Route patterns

?や+の表現で、パターンマッチングで動作するルートを設定できます。
表現式はexpress.jsの仕様を従います。

### 2-1-c. Route Parameters

動的uriパラメータ機能をサポートします。`/:parameter_name`形式で使えます。
`{{urlParam 'paramName'}}`形式で取得することができます。（Templete Helper機能）


### 2-1-d. Query Parameters

QueryStringのパラメータも利用できます。
`{{queryParam 'paramName'}}`形式で取得することができます。（Templete Helper機能）



## 2-2. Helpers

Mockoonでは、より動的で多様な機能を簡単に提供するための機能をHelperという形で提供しています。

Helperの使い方としては、`{{helperName param1 param2}}`形式で呼ぶことができるようにテンプレート化されているため、この形式合わせて、ボディー入力欄やファイルコンテンツなどで簡単に使えます。

Helperは、「HanldeBars Helper, Mockoon Custom Helper, Request Helper, faker.js Helper」が提供されています。

### 2-2-a. HandleBars Helper

Mockoonは、HandleBars機能を提供します。if else each withなどの表現式を使えます。
https://handlebarsjs.com/guide/builtin-helpers.html

### 2-2-b. Mockoon Custom helper

Mockoonが独自で具現し提供しているHelperで、Array, Math, String, Datesなどの有用な機能を提供します。
https://mockoon.com/docs/latest/templating/mockoon-helpers/

### 2-2-c. Request Helper

API リクエスト情報から、body payloadやquery parameter, cookie, host情報など、さまざまな情報を簡単に取得できる機能を提供しています。
https://mockoon.com/docs/latest/templating/mockoon-request-helpers/

### 2-2-d. faker.js Helper

faker.jsが提供している機能をMockoonでも使えます。メアドや名前、住所などの情報を任意の仮のデータとして生成し利用することができます。
https://mockoon.com/docs/latest/templating/fakerjs-helpers/

## 2-3. その他の機能

File ServingやTLS, CORS, Multi Responseなどなど、いろんな機能を提供しているので、以下の公式ドキュメントで参考できます。
https://mockoon.com/docs/latest/about/


# 3. Mockoonのコード管理とDocker環境上での実行

1と2を通して、APIを追加し、一つのローカル環境でサーバーを起動することをしました。
ここからは、追加したAPIとEnvironmentを多数の人に共有し、チーム開発での活用方法をみます。

## 3-1. Mockoon Environmentファイルの確認とコード管理

Environmentファイルとは、1で説明したように、MockAPIの定義とサーバー情報を定義したファイルです。
このファイルはjson形式でコード化されています。

中身をみると、以下のようにサーバー情報と、2で/helloとして作ったAPI情報が載っています。
つまり、このファイルをGithubなどでコード管理し、チーム開発でのテストMockAPIServerとして活用できるということになります。

```
❯ cat test-mockoon.json | jq
{
#...中略
  "port": 3001,
  "hostname": "0.0.0.0",
#...中略
  {
#...中略
      "method": "get",
      "endpoint": "hello",
      "responses": [
        {
          "uuid": "7e4e0df8-5b58-4655-98dc-dc912009f665",
          "body": "world",
```

## 3-2. Environmentファイルを指定し、Docker環境でサーバー実行

しかし、チーム全員がMockoonをインストールしGUIを使うのが、少し面倒かもしれません。
そこで、Mockoonは、CLIでの管理やDocker環境でサーバー起動を提供しています。

以下のように、ローカルファイルはもちろん、Githubレポジトリーから直接参照し、サーバーを起動することも提供しています。

```
# ローカルのenvironmentファイルを参照し実行
docker run -d --mount type=bind,source=/absolute/path/to/data.json,target=/data,readonly -p 3000:3000 mockoon/cli:latest -d data -p 3000

# githubのレポジトリーのenvironmentファイルを参照し実行
docker run -d -p 3000:3000 mockoon/cli:latest -d https://raw.githubusercontent.com/mockoon/mock-samples/main/samples/generate-mock-data.json -p 3000
```

CLI機能を含め、詳細は、以下のチュートリアルで確認できます。
https://mockoon.com/tutorials/run-mock-api-anywhere-cli/

## 3-3.　疎通テスト

では、2で作ったenvironmentファイルを利用してdockerでサーバーを起動し、curlでテストをしてみます。
以下のように、簡単にdocker環境で実行することができます。

```bash
❯ head test-mockoon.json
{
  "uuid": "0415ae77-0fe7-4baf-b92b-07819280d4d6",
  "lastMigration": 19,
  "name": "Test",
  "endpointPrefix": "",
  "latency": 0,
  "port": 3001,
  "hostname": "0.0.0.0",
  "routes": [
    {
❯
❯ docker run -d --mount type=bind,source=/Users/oh/Develop/test-mockoon.json,target=/data,readonly -p 3001:3001 mockoon/cli:latest -d data -p 3001
de956b5a8b15415b5c46ff008d5b0db404a5d2670055fde14cf6621d0746821b
❯
❯ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED              STATUS              PORTS                    NAMES
de956b5a8b15   mockoon/cli:latest   "mockoon-cli start -…"   About a minute ago   Up About a minute   0.0.0.0:3001->3001/tcp   goofy_cohen
>

❯ curl http://localhost:3001/hello
world
>
```

## 3-4. チーム開発での活用に関して

チーム開発で活用する場合は、以下の流れで利用すると良いとおもいます。

- Mockoonで、MockAPIとEnvironmentを定義
- Github Repositoryへpush
- Github RepositoryからEnvironmentを参照するdockerコマンドをチームへ共有
- 開発するときに、ローカル環境でのAPI endpointは、Mockoon MockAPIServerをendpointとして指定し開発を進める

これで、複数の人の各自のローカル環境において、同じMockAPIサーバー環境を提供することが可能となります。


# 4. 外部連携APIのMock API Server化への考察

ここでは、以下の3つの観点で、Mock API Server導入に関して考えます。

- **なぜ、外部連携APIのMock API Server化が必要か？**
- **どういう効果が期待できるか？**
- **APIのMock化にはどういう選択肢があるか？ なぜMock API Serverが良いのか？**

## 4-1. なぜ、外部連携APIのMock API Server化が必要か？

**Mock化をする核心的な理由は「依存性断絶」にあります。**

最近はウェブサービスにおいて、外部APIの連携は必須となりつつあります。
商用サービスでは、ソーシャルログインや決済代行、Eメール転送などユーザーに直接関わるものもあれば、システム監視やデータ分析もあり、ビジネス戦略を目的とした他社サービス提携の場合もあります。

外部API連携は、サービス開発の生産性の面だけではなく、元々は自社ビジネスだけでは提供できない機能や価値を提供できるという戦略面においても非常にメリットがあると言えます。

しかし、外部連携APIのインテグレーションは、以下のような、困難さをもたらす機能をサービスに搭載することと言えます。

- サービスにおいて、依存性がもっとも強い機能（テストや関心の分離が難しい）
- 制御が最も難しい機能(オーナーシェフは、API提供者に全的にあり、こちらではコントロールが難し)

そして、チーム単位開発や維持補修を非常に難しくする要因でもあります。
したがって、「どうやって、外部連携APIとアプリケーションの依存性を断絶させ、チーム単位開発と維持補修をしやすくし、生産性をあげるか？」を考える必要があると思います。

Mock API Serverは、その問いに対する一つのソリューションと言えます。

## 4-2. どういう効果が期待できるか？

Mock API Serverの導入により期待できる効果はいろいろありますが、代表的に2つを今回はあげます。

- a. チーム単位での開発生産性の向上
- b. 継続的統合とテスト自動化が容易

### 4-2-a. チーム単位での開発生産性の向上

外部連携APIのインテグレーションにおいて主にネックになる場合が多いと思います。

- 先方のAPI開発環境の準備までの待機時間
- 先方API環境のアクセス制限により、限られた環境のみ利用可能
- チーム内での仕様把握における認識のズレ

Mock APIの事前開発は、「依存性断絶」と「情報の集中管理」を可能にし、上記の問題を大幅に軽減してくれると思います。

### 4-2-b. 継続的統合とテスト自動化が容易

Mock　API Serverソリューションはスタンドアローンサービスとして構成できます。
つまり、MockClassやMockLibraryソリューションとは違い、アプリケーションコードとの依存性をほぼ完全に断絶してくれます。

これにより、以下の効果が期待できます。

- 継続的統合・テスト自動化において、外部連携API関連機能もカバー可能になる
- 仕様に変動があっても、アプリケーションコードとMockを個別で考え、追加・変更ができる

この効果は、継続的統合とテスト自動化において、既存のAPI連携部分のテストの困難さと維持補修の負担をかなり軽減してくれると思います。
また、サービスのソフトウェア品質維持をより効率的にしてくれると思います。

## 4-3. APIのMock化にはどういう選択肢があるか？ なぜMock API Serverが良いのか？

実のところ、APIのMock化に対してのソリューションは、大体以下の選択肢があると思います。

- ① （選定）Mock API Server
- ② Mockを作らない。自動テストカバレッジから該当機能を除外する
- ③ Mock Class開発
- ④ 外部連携API関連機能の階層の分離とMockLibrary利用

### 4-3-a. ① Mock API Serverを選定した理由

この中で、Mock API Serverが他の選択肢よりメリットがあい、選定した理由は以下になります。

- Mock API追加・修正が非常に簡単
- アプリケーションコードとMock機能との依存性を完全に断絶し、関心の分離が叶う。
- チームの共通認識として揃いやすい
- 情報管理と維持補修がしやすい

### 4-3-b. 他の選択肢は、どういう難しさがあるか

**■ ② Mockを作らない。自動テストカバレッジから該当機能を除外する**

この選択は、実のところよくあるかもしれません。
その理由は、「開発工数の増大」と「外部連携APIのMock化の難易度」があるのではないかなと思います。
しかし、Mock API Serverの場合は、今まで説明したように、「最小限の時間で、より簡単に」にしてくれるソリューションです。

短時間で簡単にできるであれば、Mockがもたらしてくれるメリットを取らないのは、勿体無いというのが筆者の意見となります。

**■ ③ Mock Class開発、 ④ MockLibrary利用**
この選択は、自由度が高くいろんな要件に対しても対応できるという長所がありますが、以下の難しさを抱えています。

- Mock Logic 開発・維持補修の負担
- 設計・開発・品質維持がが高難易度

実のところ、この③の方法は、Factoryみたいな提供者クラスを作るか、DI(依存性注入)　活用など、OOPやDesign Patternなどの理解が求められ、常にクリーンアーキテクチャーを保てた上での開発が必要で、④の方法はビジネスロジックの階層分離設計までも求められれ、上記の知識の上でDDD設計知識も求められるのではいでしょうか。

そうしないと、Mockを作らないという選択よりも、ソフトウェア品質がよくならないケースも多くあると思うからです。
特に、チーム単位開発になると、全員が同じ方向性で実装することは、より難しくなります。

その一番の原因は、Mock機能とアプリケーションコードとの依存性にあると、筆者は思います。
この方法は、外部APIシステムとの依存性は断絶できますが、そのために作ったMock機能との依存性が新しく生まれてしまいます。そして、維持補修において、常にアプリケーションとMock機能を同じ関心ポイントとして扱わなきゃいけなくなります。

サービスが小さい内は利点も多いですが、サービスが大きくなっているうちに、不利点が飛躍的に上がってしまうのが、この方法の難点だと思います。

# 5. Conclusion

**継続的な提供が必要なサービスにおいて、複数の外部連携APIをインテグレーションが求められるのであれば、Mock API Server導入と外部連携APIのMock化は、チーム単位開発の生産性と、維持補修においてのソフトウェア品質維持において大きなメリットが期待できるので、導入にチャレンジするべき**

というのが、結論でしょうか。

もちろん、Mock API Server導入にも課題がない訳ではありません。
「対応できるプロトコルの制限、例外ケースへの対応、管理ポイントの増加」などの課題に対して、検証は必要だと思います。

しかし、その懸念を抱えた上でも、メリットの方がはるかに大きいと思います。

実際、筆者が携わるサービスは、一つのサービスにおいて１０個を超える外部連携APIを取り組んでいて、いまだに増えつつあります。また、サービス自体、長年運用されていて、モノリシック構造の肥大なサービスとなっており、アプリケーションの複雑さは増しています。

この現状においてMock API Serverの仕組みは、「外部連携API部分の依存性断絶」を可能にし、「チーム開発をしやすくする、継続的統合とテスト自動化をしやすくする」ことで、今後の新規開発や維持補修はもちろん、モノリシック構造の改善にも、つながると期待しています。

# reference

今回の検討に当たって、以下のサイトを参考にしていますので、関心のある方はご参考いただくと、良いと思います。

https://en.wikipedia.org/wiki/Comparison_of_API_simulation_tools
https://developers.amadeus.com/blog/helpful-tools-to-create-mock-servers