Golangでモックサーバーのライブラリを実装してみた話

この記事はJX通信社Advent Calendarの4日目です。

今年の10月からJX通信社でNewsDigestというiOS版アプリの開発担当として参画してるmoaibleです。

普段からアプリ・Webページのようなクライアントサイドとサーバーサイドの専任で開発担当が分かれていると、あるあるなのがスケジュール的にAPIの方が遅れていてクライアントサイド的にはレスポンスが無いと開発が進まないようなケースです。

そこでよくある解決策としては以下のようなパターンがあるのでは無いでしょうか。

  • クライアントサイド側でレスポンスをダミーとして固定ででっち上げる
  • モックサーバー環境があって本番で返す想定のレスポンスと同じ形式をとりまで返してもらう
  • モックサーバーをローカル環境として構築し、通信せずとも本番で返す想定のレスポンスと同じ形式を返すようにする

今回は上記太字の「モックサーバーをローカル環境として構築」にフォーカスを当て、環境構築を簡単にしたい、そのためにどうしたのかを話します。

既にあるモックサーバー用のライブラリ

まず既に「モックサーバーをローカル環境として構築」するようなライブラリはいくつも存在しており有名どころだと、

wiremock.org

オプションも多く特定のパラメータに合わせて細かい制御が効くこともあってよく名前が挙がるのでは無いでしょうか、ただ難点として環境構築・モックレスポンスの調整含めて慣れるのに時間がかかる印象です。

個人的によく使っていたモックサーバーとしては、

github.com

node製で、基本的に簡単な書式のroutingファイルだけ書いて後はjsonを設置するだけでモックAPIが出来上がるので簡単なAPIのmockingであれば十分に事足りるでしょう。

ただ細かいパラメータによるハンドリングまでは行えず、例えば特定のheaderの場合に準正常系なレスポンスを返すような調整をすることができませんでした。あとroutingに変更を加える場合はいちいちstubcellを再起動させねばならず若干使い勝手として面倒な印象もありました。

そこで簡単に環境構築ができて、さらに細かいパラメータの調整も可能な自分が欲しいライブラリを自分で実装してみることにしました。

gostub

github.com

これはディレクトリ構造を元にrouting定義として細かいハンドリングによって固定のjsonを返すことを可能にすることをコンセプトとしたGolang製のモックサーバーなライブラリです。

コードを見てもらっても分かるのですが特に他のライブラリに依存することなくGolangの標準ライブラリのみを組み合わせて実装しているためライブラリ実装自体も軽量なものとなっています。

導入

この記事ではGOPATHなどのGolang自体の環境構築は割愛しますが、Golangが動く状態で下記go getなコマンドを叩いてもらうだけで完了します。

$ go get github.com/gostub/gostub

コマンド

$ gostub -h

Usage of gostub:
  -o string
        output path (e.g. 'tests' -> ./tests)
  -p string
        port number (default "8181")

helpで出力されたままですが、

$ gostub -p :ポート番号 -o :モックサーバー起点となるディレクトリ

上記2つのオプションな引数のみとなります。

Hello, World!

GET /hello/world => { "greed": "Hello, World!" }

上記のようなリクエストに対して「Hello, World!」のレスポンスを固定で返すモックなAPIを構築します。

まずモックとして返すようにするためにディレクトリ構造を合わせていきます。

.
└── hello
    └── world
        ├── $GET.json
        └── response.json

ここで出てくる、$GET.jsonresponse.json が実際にリクエスト・レスポンスに関係するjsonです。

$GET.json

{
  "default" : {
    "body": "response.json",
    "status": 200
  }
}

response.json

{ "greed": "Hello, World!" }

動作確認

これで最低限の準備が整いました、試しにgostubを起こしてcurlを叩いてみます。

$ gostub -p 8081
Start gostub server...
port: 8181, output:

これで別窓でcurlを叩くと

$ curl http://localhost:8081/hello/world
{ "greed": "Hello, World!" }

という具合にレスポンスを確認することができました。

ただこれだけだとまだ良さが分からないので更に細かい機能の使い方を紹介していきます。

routing

さっきはGETなAPIのみの一例でしたが、実は見ての通り ${HTTPメソッド}.json で各種HTTPメソッドに対応することができます。

CRUDなREST APIに対応する場合は、

.
└── hello
    └── world
        ├── $GET.json
        ├── $POST.json
        ├── $PUT.json
        ├── $DELETE.json
        └── response.json

とすることで複数のHTTPメソッドに対応したモックAPIを実現できます。

特定のパラメータによるハンドリング

パラメータ種別 key名 定義
ヘッダー header "header": { "name" : "xxx" }
パス path "path": "xxx"
Query, Bodyパラメータ param "param": { "name" : "xxx" }

上記のパラメータをroutingのjsonに細かく追記することが可能です。

{
  "default": {
    "body": "default.json",
    "status": 200
  },
  "handlers" : [
    {
      "content": {
        "body": "failed_auth.json",
        "status": 401
      },
      "header": {
        "X-USER-ID" : "invalid user id",
      }
    }
  ]
}

上の例だと X-USE-IDinvalid user id という文字列だった場合に401を返す定義になります。

起動中でも動的にjsonを設置できる

大抵のモックサーバーなライブラリだとroutingを書き換えるのに再起動しないといけなかったりするのですが、routingのjsonも含めて常に動的に内部でハンドリングをしているため起動するだけで後は動かしながら好きに編集することができます。

モックサーバーを終了させる

CIなどでモックサーバーを立ち上げてユニットテストを実施するような場合だと二重に起動して動作しないようなケースに遭遇することも稀にあります。

そこでgostubではモックサーバーを終了するために GET /gostub/shutdown を叩くことで強制的に終了することが可能です。

終わりに

いかがでしたでしょうか。

モックの開発は一長一短で本番環境に近いことがベストだとは思いつつも、いざという場面で気軽に使えるGolang製のライブラリの紹介でした。

クライアントサイドで開発してる際に困った時にはモックサーバーは十分に選択肢の1つとしてあり得ると思うので、自分たちで開発環境を良くできるように立ち回っていきたいですね 💪