Overview
jsonApiMock
RESTful APIに限らず、何かしらJSONをレスポンスとして返却するAPIをまとめてモックするアプリケーションを作った。
きっかけ
- いろんな種類のAPIをcallするアプリケーションを作っていて、テストのためにモックAPI作りたいなーと思っていた。
- が、全種類のモックAPIをそれぞれ作るのは手間がかかりすぎる。
-
json-serverはRESTfulなAPIのモックには丁度いい…んだけど、そうじゃないAPIをモックするのは難しい。
- もっとゆるーく「JSON返すAPI」を対象にしたモックツールが欲しい。
- モック用のデータセット作るのがめんどくさ過ぎる。
- 「APIの仕様が変わったって?じゃあまたデータ作り直しかい…」
- "今動いているもの"を手早くモックしたい。
できること
APIをモックできます。
対応するRequest
大抵のHttpRequestをモックできる(GET,POST etc.)
- 実際のAPIをcallする形式で、モックデータを定義できる
- Content-Type, RequestBody, QueryStringもちゃんと識別できる
- 認証情報やCookieについては識別していない
対応するResponse
今のところJSONのみ。
- モックのレスポンスとして、HttpStatusとJSONのbodyを定義できる
- 異なるHttpMethod,RequestBody,QueryStringに対して異なるレスポンスを定義できる
モックデータの作成について
- 記録したモックデータの取得(JSON), およびそのJSONを用いたモックデータの登録ができる
-
実際のAPI呼び出しを盗み見て、モックデータを作成できる
モックデータの形式は↓のような感じ。
リクエストの同一性は、request内の各fieldの値が一致しているかどうかでチェックしている。
(ただしheaderとかbodyの一部は一致チェックには使用していない)
c.f. ApiMockRequest.hash
{
"id": "82b16c33c5060e5d57e9d2111d465c1c",
"request": {
"body": "",
"endpoint": "/users",
"headers": {
"accept": "*/*",
"host": "localhost:8080",
"user-agent": "curl/7.43.0"
},
"method": "GET",
"params": [
{
"key": "name",
"value": "Jiro"
}
]
},
"response": {
"body": "[\n {\n \"name\": \"Jiro\",\n \"id\": 3\n }\n]",
"httpStatus": 200
}
}
使い方
各機能の詳細はREADMEに。
(各機能のサンプルもそちらに)
動作環境
- JDK 1.8以降
- Maven 3.x
Spring Bootで組んであるので、使用感はそれに準拠している。はず。
起動方法
mvn spring-boot:run
か、固めたjarを実行
mvn package
java -jar target/jsonAPIMock.jar
基本的な利用フロー
- モックしたいリクエストを投げる
(/apimock/request/{mockTargetPath}
)
=> モックデータのIDが返ってくる - 1でモックしたリクエストに対して返却するレスポンス(Body, HttpStatus)を投げる
(/apimock/response/{id}/{responseStatus}
)
=> 更新したモックデータのIDが返ってくる - 実際のAPIをcallするように、jsonApiMockをcallする
(/apimock/execute/{mockTargetPath}
)
=> 2でモックしたレスポンスが返ってくる
例としては以下のような感じ。
# /test/hoge というエンドポイントのモックリクエストを登録
curl http://localhost:8080/apimock/request/test/hoge?name=John
## > 3440f2e01a9d2779b2823811b5e5cf9c
# /test/hoge のモックレスポンスを登録
curl -H "Content-type: application/json" -X POST http://localhost:8080/apimock/response/3440f2e01a9d2779b2823811b5e5cf9c/200 -d '
{"greeting" : "hello, John!"}'
## > 3440f2e01a9d2779b2823811b5e5cf9c
# 登録したモックデータを、APIモックとして利用する
curl http://localhost:8080/apimock/execute/test/hoge?name=John
## > {"greeting" : "hello, John!"}
Spyモード
jsonApiMockをクライアントアプリとAPIの間に噛ませることで、
「実際にAPI呼び出しを行いながら、モックデータを自動記録する」
ことができる。
1.client側が、jsonApiMockの/spy
エンドポイント経由で実際のAPIをcallする
2. jsonApiMockは、以下の3つの処理を行う
2-1. client側から受けたリクエスト内容を実際のAPIにリクエストする
2-2. 実際のAPIのレスポンスを加工せず、client側に返却する
2-3. リクエスト内容とレスポンス内容をセットにして、モックデータとして記録する
3. client側は、実際のAPIを直接callしたときと同じ使用感で、処理を続行する
具体的な手順は以下の通り。
# 実際に使用するAPIのパスをセットして起動
java -jar target/jsonAPIMock.jar --apimock.spy-target-url="http://gturnquist-quoters.cfapps.io"
# もしくは、/envエンドポイントを利用して、起動中に動的にパスを変更
curl -X POST http://localhost:8080/apimock/env -d apimock.spy-target-url="http://gturnquist-quoters.cfapps.io"
## > {"apimock.spy-target-url":"http://gturnquist-quoters.cfapps.io"}
# 起動直後なのでモックデータが存在しないことを確認 (Optional)
curl http://localhost:8080/apimock/data
## > []
# /spy に対してAPI Requestを投げる
curl http://localhost:8080/apimock/spy/api/random
## > {"type":"success","value":{"id":12,"quote":"@springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib"}}
# ↑これは実際のAPI(http://gturnquist-quoters.cfapps.io/api/random)のレスポンスそのもの
# さっきのAPIリクエストについて、データが記録されていることを確認 (Optional)
curl http://localhost:8080/apimock/data
## > [{"id":"89150a098c708c1cfc2c26c03b867902","request":{"endpoint":"/api/random","method":"GET","contentType":null,"body":"","params":[]},"response":{"body":"{\"type\":\"success\",\"value\":{\"id\":12,\"quote\":\"@springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib\"}}","httpStatus":200}}]
# /execute 経由で、記録したモックデータを利用
curl http://localhost:8080/apimock/execute/api/random
## > {"type":"success","value":{"id":12,"quote":"@springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib"}}
# ↑このレスポンスは、記録されたデータを返しているだけで、実際のAPIはcallしていない
この仕組みがあることで、モックデータの作成がだいぶ楽になると思う。
その他の機能
いくつか便利エンドポイントも作った。
/apimock/data [GET]
記録されているモックデータの一覧を取得
/apimock/data/{id} [GET]
指定したIDのモックデータを取得
/apimock/data [POST]
モックデータ形式のjsonを受け取って、モックデータとして記録する
/apimock/dataList [POST]
/apimock/data
のList版(複数同時登録)
今後の展望
心地よく使うために、追加していきたい機能とか。
- モックデータの永続化
- アプリケーションを終了すると、記録したデータは全て消える。
-
/apimock/data
で記録済みデータを取得しておいて、次回起動時に/apimock/dataList
を使って突っ込むというのが現状取りうる運用スタイルになる。 - json-serverのように都度ファイル書き込み&起動時にファイル読み込みできるようにしておいてもいいかも。
-> (追記) 固定ファイル名でsave/loadするためのEndpointを追加
まとめ
実際のサービス開発にどれくらいの効果があるのかはまだ分からないけれど、
APIのモック周りで困っている人たちの一助となれるとうれしい。
2018-10-02 追記
このツールを作成した直後にWireMockでほとんど同じことが出来るのが分かったので、完全に実装を放置している。
WireMockについては既に多くの記事で言及されているので、APIモックに悩んだらそちらを使う方がオススメである。
(WireMockでも足りないものがある場合、こちらのツールを拡張するかWireMockにContributeする予定)
参考文献
json-serverを試す上で、下記の記事を参考にさせていただきました。