↔️

Prism mock に BasePath を適用したい人生だった

2024/08/13に公開

あらすじ

OpenAPIの開発環境を構築中にPrismでモックサーバーを立ち上げようとしたところ、BasePathを適用することができなかった。つまり /api/v1/xxxx のようなエンドポイントを設定したかったのですが、どうやら OpenAPI 3.0 では実現することが難しいようでした。

なぜなのか、どうしたらよいのか。

BasePath について

まず、BasePathという概念について。

APIのURLに /api/v1 のような接頭パスを付与することがよくある。管理上APIのURLは /api のようなパスに束ねておきたいし、後方互換性などの理由からバージョニングのため /v1 のようなパスから配信したりします。

当然このパスはすべてのAPIエンドポイントに共通して付与されるものだから、一々 path に含めておくのは無駄だし、共通設定として記載しておきたい。OpenAPI 3.0 の仕様では、 servers.url の指定がそれにあたるようですが、Prismによるモックサーバーではその指定は考慮されません。

servers:
  - url: /api/v1
path:
  /hello:
    get:

などのように指定した場合、期待したいリクエストは GET http://localhost:4010/api/v1/hello なのだけど、これは404になる。 http://localhost:4010/hello なら取得できる。

BasePath に関するディスカッション

cf) option to specify basepath in prism mock server

ここでPrismのモックサーバーにBasePathを適用するための方法について議論が交わされていました。ものすごくざっくりと紹介します。

ユーザー側の主張

prism mock--basepath /api/v1 のようなオプションを追加してモックサーバーのURLにBasePathを適用できるようにしてほしい。

開発側の主張

そのような機能を実装する予定はない。
FAQ に記載してあるように、ユーザー間で混乱が生じるからだ。

ユーザー側の主張

オプションで追加するのだからデフォルトの挙動は変わらないのに、誰が混乱するっていうんだい?

雰囲気で読んでみたが多分こんな感じ。とりあえず、そういった機能は実装するつもりはなさそうだというのが読み取れました。

結局お前が頼りだ、Nginx

上のディスカッションでも一部のエンジニアが触れているように、結局Nginxでproxyしてなんとかするというのが現実的な解決策です。

例えばの前提として、フロントエンドの開発環境が :3000 で、Prismのモックサーバーは :4010 で立ち上がっていて、API の BasePath は /api/v1 を想定する。これらを束ねて同じオリジン( localhost:4000 )から配信出来るようにnginxをセットアップする。

  • フロントエンドDevサーバー(Next.js) :3000
  • Prismモックサーバー :4010
  • nginx :4000

まずはnginxの設定ファイルを書いてプロジェクトルートにでも置いておく。 nginx自体はdockerで立ち上げるので、 proxy_pass のURLにはホストOSを指す host.docker.internal を使う。

nginx.conf
server {
  listen 80;
  server_name localhost;

  location / {
    proxy_pass http://host.docker.internal:3000/;
  }

  location /api/v1/ {
    proxy_pass http://host.docker.internal:4010/;
  }
}

nginxの起動はnpmスクリプトで行う。

package.json
"scripts": {
  "dev": "next dev -H 0.0.0.0",
  "api:mock": "prism mock ./openapi/api.yaml",
  "nginx": "docker run --rm -v ${PWD}/nginx.conf:/etc/nginx/conf.d/default.conf -p 4000:80 nginx"
},

next dev-H 0.0.0.0 を渡しているのは、WSL環境で起動した場合にこれをしないとアクセスできなかったからで、環境によっては不要かもしれません。

あとは devapi:mock を起動してから nginx を起動すれば localhost:4000 でプレビューできるはず。Next.jsアプリ側からAPIにアクセスするには /api/v1/hello にリクエストを送る。

const res = await fetch("/api/v1/hello");

おわりに

一応無事開発環境は整ったわけですが、2つ起動すればいいはずのところを3つのスクリプトを起動しなければならないのはモヤるポイントではあります。まさにこのモヤポイントが上のディスカッションで盛んに議論されていたわけで。

(とはいえオリジン揃えたりするなら結局nginxの力は借りなきゃいけないのか?)

ということでよりスマートな解決方法をご存知の方がいらっしゃったら是非教えてください。

Discussion