.../articles/

OpenAPI×Stoplight Prismでモックサーバーをたてる

OpenAPIをバックエンドとフロントエンドの橋渡し役としてさらに活用すべく、OpenAPIのスキーマをもとにモックサーバーをたてることのできるStoplight Prismを試してみました。

OpenAPIの活用について

弊社ではこれまでにOpenAPIをサーバーサイドのAPIのテスト、フロントエンドのクライアントコードの自動生成などに活用してきました。

現状の課題

自動生成されたクライアントコードがあったとしても返すデータがなければマークアップや組み込みを進めるには少し不便です。
せっかくスキーマから型まで生成しているのに、データがないので仮組みしてあとから実データにあわせて修正では無駄が多いように思います。

また、プロジェクトの初期段階などにバックエンドとフロントエンドの担当者がそれぞれがローカル環境で開発を行っている状態もあり、この時にフロントエンドの担当者に「APIサーバーをローカルで動かしてください」というのはハードルが高いこともあります。
ローカルでプログラミング言語やフレームワークのセットアップをしたりDockerを使ったりすることはできますが、作業の度に確認が発生するのは好ましくありません。

このようにAPIの実装はどうしても組み込みをブロックしてしまうので、OpenAPIのスキーマを定義した時点でバックエンドとフロントエンドが同時に開発をスタートできる状態になるのがよいと考えています。

OpenAPI → モックサーバー

バックエンドとフロントエンドの実装を切り分けるときにモックサーバーを使うという方法が考えられます。

前述の通り初期のマークアップや組み込みの段階でAPIサーバーをローカルにたてつつテストデータを用意するのは負担が大きく、モックサーバーのために別のデータを準備するのもあまり効率がよいとはいえません。
できれば複雑なセットアップなしでOpenAPIの定義ファイルとコマンド一発でできるぐらいが理想的です。

前提として「OpenAPIのスキーマを正とする」という条件をおけば、バックエンドはスキーマを満たすよう実装を進め、フロントエンドはスキーマに基づくデータを受け取る前提で組み込みを進めることができます。

これを実現できるのがStoplightの Prism というツールです。

※StoplightはAPI開発を効率化できるツールなどを開発しておりStoplight StudioはOpenAPIのスキーマをGUIで編集できるツールでこちらもおすすめです

Prismを使うとOpenAPIのスキーマをもとにリクエストのバリデーションやダミーデータのレスポンスを返すモックサーバーを簡単にたてることができます。

Prismを活用すればOpenAPIのスキーマができた時点でフロントエンドはとりあえずPrismでモックサーバーを立てつつ実装を進めてください、とできるのはないかと思います。


Prismを試す

インスール

Prismはいくつかインストール方法があるのですが、フロントエンドエンジニアが作業する場合npmまたはyarnがわかりやすいかと思います。

# インストール方法はお好みで
$ npm install -g @stoplight/prism-cli
# 動作確認したバージョンは4.1.0
$ prism mock --version
4.1.0

モックサーバー起動

まずはリポジトリに用意されているOpenAPIスキーマのサンプルファイルを使ってPrismを起動してみるとエンドポイントの一覧が表示され、モックサーバーが起動しました。
ポート番号などはオプションで変更可能です。

$ prism mock https://raw.githubusercontent.com/stoplightio/prism/master/examples/petstore.oas3.yaml
[18:26:51] › [CLI] …  awaiting  Starting Prism…
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/no_auth/pets?name=saepe
[18:26:52] › [CLI] ℹ  info      POST       http://127.0.0.1:4010/no_auth/pets
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/no_auth/pets/findByStatus?status=sold&status=available&status=pending&status=pending&status=sold&status=available&status=available&status=available&status=pending&status=pending&status=sold&status=sold&status=available&status=available&status=sold&status=pending&status=available&status=pending&status=pending&status=sold
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/no_auth/pets/findByTags?tags=aut&tags=id&tags=ut&tags=sapiente&tags=molestiae&tags=nostrum&tags=magni&tags=facere&tags=enim&tags=vero&tags=sit&tags=beatae&tags=consequatur&tags=facere&tags=unde&tags=eveniet&tags=aut&tags=et&tags=rem&tags=sint
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/no_auth/pets/421
[18:26:52] › [CLI] ℹ  info      POST       http://127.0.0.1:4010/no_auth/pets/801
[18:26:52] › [CLI] ℹ  info      POST       http://127.0.0.1:4010/pets
[18:26:52] › [CLI] ℹ  info      PUT        http://127.0.0.1:4010/pets
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/pets/findByStatus?status=available&status=available&status=available&status=sold&status=pending&status=pending&status=available&status=available&status=pending&status=available&status=available&status=sold&status=pending&status=sold&status=pending&status=available&status=available&status=available&status=sold&status=available
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/pets/findByTags?tags=modi&tags=laudantium&tags=ea&tags=nihil&tags=ab&tags=quod&tags=quis&tags=voluptatem&tags=quia&tags=et&tags=cum&tags=et&tags=dolor&tags=odit&tags=deleniti&tags=est&tags=voluptate&tags=molestias&tags=illo&tags=id
[18:26:52] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/pets/785
[18:26:52] › [CLI] ℹ  info      POST       http://127.0.0.1:4010/pets/863
[18:26:52] › [CLI] ℹ  info      DELETE     http://127.0.0.1:4010/pets/973
[18:26:52] › [CLI] ℹ  info      POST       http://127.0.0.1:4010/pets/939/uploadImage
# 一部略
[18:26:52] › [CLI] ▶  start     Prism is listening on http://127.0.0.1:4010

いくつかエンドポイントにアクセスして挙動を確認してみましょう。

  • GET http://127.0.0.1:4010/no_auth/pets?name=saepe

このエンドポイントにアクセスすると、スキーマのexampleで定義されたレスポンスが返ってきました。

$ curl -i 'http://127.0.0.1:4010/no_auth/pets?name=saepe'
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Content-type: application/json
Content-Length: 34
Date: Fri, 23 Oct 2020 09:39:42 GMT
Connection: keep-alive
Keep-Alive: timeout=5

[{"name":"a_name","photoUrls":[]}]

ちなみにこのエンドポイントはクエリパラメーター name が必須となっているので、パラメータが不足しているとバリデーションエラーで 422 を返します。

$ curl -i 'http://127.0.0.1:4010/no_auth/pets'
HTTP/1.1 422 Unprocessable Entity
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
content-type: application/problem+json
Content-Length: 376
Date: Fri, 23 Oct 2020 09:41:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"type":"https://stoplight.io/prism/errors#UNPROCESSABLE_ENTITY","title":"Invalid request body payload","status":422,"detail":"Your request is not valid and no HTTP validation response was found in the spec, so Prism is generating this error for you.","validation":[{"location":["query"],"severity":"Error","code":"required","message":"should have required property 'name'"}]}
  • GET http://127.0.0.1:4010/pets/785

前の例は認証不要なエンドポイントでしたが、このエンドポイントは認証情報がないアクセスは 401 となりました。

$ curl -i 'http://127.0.0.1:4010/pets/458'                                                                                                                   18:49:12
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
sl-violations: [{"location":["request"],"severity":"Error","code":401,"message":"Invalid security scheme used"}]
Content-type: application/json
Content-Length: 39
Date: Fri, 23 Oct 2020 09:49:46 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"code":-2147483648,"message":"string"}

securityで定義されているようにヘッダに api_key を追加すると正常なレスポンスが返ってきました。
api_key の値は問わず、存在しているかどうかが検証されるようです。

$ curl -i 'http://127.0.0.1:4010/pets/458' -H 'api_key: key'                                                                                                 18:51:54
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Content-type: application/json
Content-Length: 126
Date: Fri, 23 Oct 2020 09:52:17 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"id":2,"category":{"id":1,"name":"Felis"},"tags":[{"id":1,"name":"pet"}],"name":"Fluffy","status":"available","photoUrls":[]}
  • POST http://127.0.0.1:4010/no_auth/pets

POSTの場合でも同じ要領で、リクエストボディの必須項目を定義している場合はバリデーションをかけてくれます。

サンプルのスキーマではこのエンドポイントに200番台のレスポンス定義がないためエラーになっています。
レスポンスのステータスや内容を決定するロジックはこちらに詳しく書かれています。

$ curl -i -XPOST 'http://127.0.0.1:4010/no_auth/pets' -H 'content-type: application/json' -d '{"name": "cat", "photoUrls": []}'
HTTP/1.1 500 Internal Server Error
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
content-type: application/problem+json
Content-Length: 148
Date: Fri, 23 Oct 2020 10:05:32 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"type":"https://stoplight.io/prism/errors#NO_SUCCESS_RESPONSE_DEFINED","title":"No response in the range 200-299 defined","status":500,"detail":""}
  • レスポンスの内容を動的に変更する

Prismには dynamic というオプションがあり、これを指定することで毎回違う内容のレスポンスを返してくれるようになります。
値はスキーマに定義されたプロパティの型に応じてFaker.jsで生成しているようです。

$ prism mock -d https://raw.githubusercontent.com/stoplightio/prism/master/examples/petstore.oas3.yaml
$ curl 'http://127.0.0.1:4010/no_auth/pets?name=saepe'
[
  {
    "name": "sin",
    "photoUrls": [
      "et nostrud labore veniam ut",
      "laboris enim",
      "pariatur cupidatat ad est ullamco",
      "exercitatio",
      "non eiusmod laboris",
      "aute in",
# 長いので省略

動的というかランダムなので細かい挙動の制御をするのは難しいかもしれません。
データの型を詳細に定義していればそれに応じた内容を返してくれるので、可能な範囲でスキーマのData Typesを書くようにしておくとよさそうです。
メールアドレスであれば type: string に加えて format: email 、テーブルのIDなら type: integer に加えて minimum: 1 などなど。

今後オプションでレスポンスデータを生成する挙動を細かく設定できるようになるとより使いやすくなりそうだと思いました。


まとめ

Prismを試したみた感じでは実行するのは簡単ですが、レスポンスのデータを細かく制御するのは難しそうです。
それでもOpenAPIのスキーマに基づいた挙動が保証されたモックサーバーを使うことで、APIの実装によりフロントエンドの作業がブロックされる状態は少なからず解消できるように思いました

まだ構想段階ではあるのでフロントエンドのエンジニアとも探りつつ、よりよい開発フローを作り上げていきたいと思います。

.../articles/

Articles

記事

AWS AmplifyにmonorepoのNext.js(App Router)をデプロイする

AWS AmplifyにmonorepoのNext.js(App Router)をデプロイする

monorepo管理しているNext.jsをAmplifyにデプロイしようとした際にいくつか躓く内容があったのでまとめておきます。

リモートワーク・オンライン会議でも、スムーズに制作を進めるために大切なこと[資料編]

リモートワーク・オンライン会議でも、スムーズに制作を進めるために大切なこと[資料編]

コロナ禍の影響により、リモートワークの導入をおこなっている制作会社も多く、実際に弊社でも導入しています。

売れるECサイトデザインを作るために。参考にしたいおしゃれな事例の探し方。

売れるECサイトデザインを作るために。参考にしたいおしゃれな事例の探し方。

売れるECサイトのデザインは、「この形式」という決まりはありません。ECサイトで売り上げを上げるなら、しっかりとしたコンセプトと、コンセプトを決定するまでのリサーチが必要です。

制作会社の考える、業務効率化ツールのおすすめ。個人でも使いやすいサービスなど。

制作会社の考える、業務効率化ツールのおすすめ。個人でも使いやすいサービスなど。

新型コロナウイルス感染拡大の影響で、リモートワークが主流になり、弊社でも週のほとんどは各自宅で作業をしています。

Figmaでデザインのコミット履歴を残せるプラグイン【Thought Recorder】をリリースしました

Figmaでデザインのコミット履歴を残せるプラグイン【Thought Recorder】をリリースしました

Figmaを利用するWebデザイナーの助けになれると嬉しいです。使い方は本記事をご覧ください。

ECの構築方法、おすすめのECサービス。

ECの構築方法、おすすめのECサービス。

ファッションや家電、スーパーの買い物でさえもECサイトを利用することが当たり前になりました。加えて新型コロナウイルスの影響もあり、弊社にも「どんなプラットフォームを利用したら良いか」「どれくらいコストがかかるのか」などECに関するさまざまなご相談を頂きます。

FastAPIのスキーマクラスをOpenAPIから生成する方法

FastAPIのスキーマクラスをOpenAPIから生成する方法

PythonでAPIを構築する要件があり、フレームワークに比較的モダンなFastAPIを採用しました。FastAPIはバックエンドの開発を行えば自動でOepnApi定義を生成する機能が備わっていますが、今回はこれを使わず、事前に用意したOepnApi定義からFastAPIで利用するスキーマクラスを生成する方法を紹介します。

Laravel 日本一解りやすい全文検索のマイグレーション記載方法解説

Laravel 日本一解りやすい全文検索のマイグレーション記載方法解説

Laravel + MySQLで全文検索を実装する

GiFT1号目新卒デザイナーの2021年振り返り

GiFT1号目新卒デザイナーの2021年振り返り

いつの間に、年末ですね。入社してもう、9ヶ月も立っていたようです。2021年の振り返りを記事にしました。

TimesclaeDBのデータ圧縮に関して

TimesclaeDBのデータ圧縮に関して

TimescaleDBはデータベース内の一部のテーブルを時系列データとして扱えるPostgreSQLの拡張です。PostgreSQLの機能拡張なので非常に手軽に導入できます。今回はこのTimesaceDBの圧縮について調べたので備忘録として書き綴りました。

すべての記事

お問い合わせ