stoplight.io prism

Page content

Stoplight 社の提供する製品やオープンソースのうち、 Prism について詳細を記録する

Mock

mock と proxy あるうちの mock 側。

base path の考え方

  • そもそも spec でベースパスを指定するには servers[].url'http://example.com/v1/base' と指定し、そこから枝分かれするものは paths'/cats/{catName}' '/dogs/{dogName}' などと記述する
  • この spec で prism を起動すると /v1/base という部分は失われ、 http://0.0.0.0/cats/{catName} http://0.0.0.0/dog/ {dogName} などが有効なパスになるので要注意。
  • paths にフルパスを指定するようにすれば、回避可能。 ('/v1/base/cats/{catName}' '/v1/base/dogs/{dogName}')

Prefer ヘッダでレスポンスを操る

色々便利よ

1. status code を操作

以下のようにすると status code 400 を要望できる。

$ http -v GET http://localhost:4010/ Prefer:code=400
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:4010
Prefer: code=400
User-Agent: HTTPie/2.0.0
---
HTTP/1.1 400 Bad Request
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: *
Connection: keep-alive
Content-Length: 85
Content-type: application/json
Date: Wed, 29 Apr 2020 20:34:58 GMT

{
    "errorCode": -81152480,
    "errorMessage": "non labore sunt sint Duis",
    "moreInfo": "ipsum"
}

ただし、 400 の仕様が記述されていないと動作しないので注意

HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Length: 191
access-control-allow-credentials: true
access-control-allow-headers: *
access-control-allow-origin: *
access-control-expose-headers: *
content-type: application/problem+json
date: Tue, 05 May 2020 08:42:03 GMT
sl-violations: [{"location":["response"],"severity":"Warning","message":"Unable to match the returned status code with those defined in the document: 201"}]

{
    "detail": "Requested status code 400 is not defined in the document.",
    "status": 404,
    "title": "The server cannot find the requested content",
    "type": "https://stoplight.io/prism/errors#NOT_FOUND"
}

2. example response を要求

example ID を指定するとそれをお返ししてくれる。あら便利! リクエストの example ID を指定したらリクエストに対してもバリデーションかけてくれると嬉しいかも…?

3. dynamic response を要求

起動時の -d オプションの有無をこれで上書きできる。

Prefer: dynamic=true
Prefer: dynamic=false

4. x-faker キーワードを仕様に埋め込んでリアルな dynamic response を。

x-faker キーワードを OAS のプロパティのスキーマに入れる(format や example と同じ要領で)と、 JSON Schema Faker (実体はどうも Faker.js に依存しているらしい) による、指定フォーマット(メールアドレス、電話番号、等々)のランダムな値の生成ができるらしい。 Faker.js 公式の demo page で各フォーマットがわかり、 JSON Schema Faker で実際に試せる。

これが JSON schema (YAML にて失礼):

type: object
properties:
  id:
    type: string
    pattern: '[0-9a-f]{32}'
  name:
    type: string
    x-faker: random.uuid
  phone:
    type: string
    x-faker: phone.phoneNumber

それに対して生成される JSON object をいくつか:

{
  "id": "86efee7471cf7b04fa570e6c68f74e27",
  "name": "464ad31c-be66-4168-af5a-a5f366ea6c71",
  "phone": "528-042-3204"
}

{
  "id": "41f3927da2b6986119360b71e09e2ebc",
  "name": "24dca20c-bc30-4ec8-a2e6-bd1d44bef41b",
  "phone": "473-093-2555 x19174"
}

request validation

  • __server クエリパラメータで OAS に定義されたサーバURLと一致するかどうかのチェックもできるらしいが、わざわざ query を書く時点でちょっと違う気がする。飛ばし先は相変わらず localhost:4010 だったりするわけなので。

Validation Proxy

mock と proxy あるうちの mock 側。

base path の考え方

  • proxy 自体のベースパス: mock と同じように spec を解釈する
  • backend のベースパス: CLI で指定するベースパスがそのまま使われる。
    • 例: proxy 起動コマンドが docker run --rm -it -v $(pwd):/tmp -p 4010:4010 stoplight/prism:3 proxy -h 0.0.0.0 '/tmp/spec.yaml' 'http://example.com/v1/base/' なら、 proxy に http://localhost:4010/cats/{catName} というフルパスでアクセスがあったら、 backend には http://example.com/v1/base/cats/{catName} というフルパスでアクセスに行く

その他使い方

  • mock は callback にも対応している。 … いや、そもそも OAS での callback の指定の仕方を知らなかった。使うとなれば便利なんだろうなぁ。あんまり対応しているツール無いんじゃなかろうか。

  • CORS はデフォルトで寛大な設定で、 Allow any method and origin って感じ。これもいじれるっぽい。

  • 複数の OpenAPI documents を mock するなら、 docker-compose とかで頑張れ。 1 container for 1 spec file だ。 nginx の reverse proxy をフロントに、裏に1ファイルずつ prism mock コンテナを用意する、とか。

  • Postman Collection の JSON から prism mock を生成することもできるらしい。ただし Postman 自身が OpenAPI 準拠ではない機能を持っていたりするので、フル活用は出来ないかも。自分的には Postman はもう API client に成り下がっているので、充実したテストは不要。 (request を collection として保存できたり、環境変数を管理できたり、それらをチームで共有できる点は大変便利に使っているよ。あくまでテスト自動化に使っていないだけ)

mock と proxy を組み合わせる

何ができるかというと、クライアントのリクエストもサーバのレスポンスもバリデーションがかかる。つまり、 spec の request, response の正しさとクライアントの実装が同時に検証される。

  • ローカルでそれをやる例として、以下の2つ同時に稼働させれば良い:
    • proxy: docker run --rm -it -v $(pwd):/tmp -p 4011:4010 stoplight/prism:3 proxy -h 0.0.0.0 '/tmp/spec.yaml' 'http://<your_local_if_addr>:4010/'
    • mock: docker run --rm -it -v $(pwd):/tmp -p 4010:4010 stoplight/prism:3 mock -h 0.0.0.0 -d '/tmp/spec.yaml