🍣

WireMockを使用した外部接続APIのモック化

に公開

はじめに

こんにちは、WealthNaviでバックエンドエンジニアを担当しているかるかんです。
今回は、外部接続APIをWireMockでモック化した際の備忘録をまとめます。

概要

参加しているプロジェクトで、他社が提供するAPI(以下、外部接続APIと呼称)を呼び出す機能の開発がありました。しかし、その外部接続APIはプロダクトの制約上、開発中に自由に呼び出すことができませんでした。
システム概要
しかも、そのAPIは以下のような挙動をしたため、開発中になるべく実際のレスポンスに近いモックサーバーの作成をする必要がありました。

・リクエスト項目が複数あり、その組み合わせでレスポンスのパターンも複数に分岐する
・タイムアウトした場合のハンドリングが次処理に重要

以上の背景から、今回のモックサーバー作成にはWireMock を導入しました。WireMockは、リクエスト-レスポンスのパターンをJSONファイルだけで簡単に定義できるため開発時間の短縮になります。加えて、リクエストマッチング機能が充実しており多数のレスポンスパターンを配置できる点やレスポンスに要する時間を設定できるのでタイムアウトも表現できる点が、今回の要件に合致していました。

WireMockの設定方法

WireMockにはJavaでの起動方法などもありますが、ここではDockerでの起動方法のみを紹介します。

ディレクトリ構成の作成

次に、以下のディレクトリ構成を作成します。

└── wiremock
    ├── __files
    └── mappings

スタブ定義ファイルの作成と配置

まず、以下のようなスタブ定義(JSON)ファイルを作成し、前項で作成したmappingsディレクトリに配置します。なお、このスタブ定義は複数配置することができます。

{
  "request": {
    "method": "GET", 
    "url": "/v1/user"
  },
  "response": {
    "status": 200,
    "jsonBody": {
      "name": "Taro"
    }
  }
}

WireMockの起動(Docker)

以下のコマンドを作成したwiremockディレクトリの一つ上階層のディレクトリで実行し、Dockerを起動することで、mappingsフォルダに配置したスタブ定義が自動で読み込まれます。

 docker run -d --rm -p 9091:8080 \
  -v $(pwd)/wiremock/mappings:/home/wiremock/mappings \
  wiremock/wiremock:latest

以降、curl等で打鍵すると想定したレスポンスが返却されます。

curl -i http://localhost:9091/v1/user
HTTP/1.1 200 OK
Matched-Stub-Id: f33d4d4c-c784-4d07-b61b-7b407ef5bd3c
Transfer-Encoding: chunked

{"name":"Taro"}                      

リクエストマッチング

WireMockはリクエストマッチング機能が充実しています。今回のモック作成でWireMockを選定した理由のひとつは、パス・クエリパラメータ・リクエストボディに対して正規表現によるパターンマッチングが可能であり、リクエストとレスポンスの組み合わせを詳細に定義できる点です。特に、リクエストボディまで含めてマッチング条件として細かく評価したかったため、今回の要件に対してWireMockは有力な選択肢でした。

リクエストマッチングの記述例を以下に示します。

  "request": {
    "method": "GET",
    "urlPathPattern": "/v1/[^/]+/user",// パスのみの正規表現一致
    "queryParameters": { // クエリパラメータの条件指定
      "id": { "equalTo": "12345" }, // 完全一致
      "status": { "matches": "^(success|failure)$" }, // 正規表現一致
      "email": {"contains": "@example.com"} // 部分一致
    },
    "bodyPatterns": [
      {"equalToJson" : "{ \"amount\": 10000 }"}, // JSON完全一致
      { "matchesJsonPath": "$[?(@.amount == 10000)]" } // JSONPathでの条件一致
    ]
  }
対象 判定名 判定内容
パス urlPathPattern パスのみの正規表現一致
クエリパラメータ queryParameters/ [項目名] / equalTo 完全一致
クエリパラメータ queryParameters/ [項目名] / matches 正規表現一致
クエリパラメータ queryParameters/ [項目名] / contains 部分一致
ボディ bodyPatterns/ equalToJson JSON完全一致
ボディ bodyPatterns/ matchesJsonPath JSONPathでの条件一致

タイムアウト

WireMockでは下記のようにレスポンスパターンのfixedDelayMillisecondsの項にレスポンス返却までに経過する時間を設定できるため、こちら側の規定時間を超えるようにレスポンス時間を設定すればタイムアウトのケースもテストできます。

  "response": {
    "fixedDelayMilliseconds": 76000
  }

結果

上記のようなリクエストマッチングを用いた設定によって、外部接続APIに対するリクエスト-レスポンスパターンをJSONで簡単に複数用意できました。
WireMockを使えば詳細なレスポンスパターンを簡単に早く用意できます。これにより結合テスト前に外部APIのレスポンスパターンを再現できるため、実装の分岐網羅やエラーハンドリングの確認を早い段階で行うことができます。

WealthNavi Engineering Blog

Discussion