LoginSignup
8
12

More than 5 years have passed since last update.

jsonApiMock - JSONを返すAPIのMockアプリケーション

Last updated at Posted at 2016-07-10

Overview

jsonApiMock
RESTful APIに限らず、何かしらJSONをレスポンスとして返却するAPIをまとめてモックするアプリケーションを作った。

jsonApiMock_simpleflow.png

きっかけ

  • いろんな種類の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呼び出しを盗み見て、モックデータを作成できる:sunglasses:

モックデータの形式は↓のような感じ。
リクエストの同一性は、request内の各fieldの値が一致しているかどうかでチェックしている。
(ただしheaderとかbodyの一部は一致チェックには使用していない)
c.f. ApiMockRequest.hash

sample-mock-data.json
{
    "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を実行

package_and_run.sh
mvn package
java -jar target/jsonAPIMock.jar

基本的な利用フロー

トップの図を再掲。
jsonApiMock_simpleflow.png

  1. モックしたいリクエストを投げる
    (/apimock/request/{mockTargetPath})
    => モックデータのIDが返ってくる
  2. 1でモックしたリクエストに対して返却するレスポンス(Body, HttpStatus)を投げる
    (/apimock/response/{id}/{responseStatus})
    => 更新したモックデータのIDが返ってくる
  3. 実際のAPIをcallするように、jsonApiMockをcallする
    (/apimock/execute/{mockTargetPath})
    => 2でモックしたレスポンスが返ってくる

例としては以下のような感じ。

simple_sample
# /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モード :sunglasses:

jsonApiMockをクライアントアプリとAPIの間に噛ませることで、

「実際にAPI呼び出しを行いながら、モックデータを自動記録する」

ことができる。

大体こんな↓仕組み。
jsonApiMock_spymode.png

1.client側が、jsonApiMockの/spyエンドポイント経由で実際のAPIをcallする
2. jsonApiMockは、以下の3つの処理を行う
2-1. client側から受けたリクエスト内容を実際のAPIにリクエストする
2-2. 実際のAPIのレスポンスを加工せず、client側に返却する
2-3. リクエスト内容とレスポンス内容をセットにして、モックデータとして記録する
3. client側は、実際のAPIを直接callしたときと同じ使用感で、処理を続行する

具体的な手順は以下の通り。

spy_sample
# 実際に使用する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を試す上で、下記の記事を参考にさせていただきました。

8
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12