LoginSignup
1
0

More than 1 year has passed since last update.

AWS Amplify mock apiでsubscriptionを快適に使用するためにプロキシ環境を作成したよ(NextJS)

Last updated at Posted at 2022-03-22

経緯

  • Amplify mock api は、ローカル開発を加速させることができるので非常に便利
  • しかし、現状(2022年3月)時点では、チュートリアルに書かれた方法では動作しない
  • AppSyncを使いたい大きな動機が、subscriptionであり、どうしてもローカルでシミュレートしたい

対応方法

  • 結局のところ、mock apiのサーバ自体はsubscriptionに対応している
  • しかし、aws-sdkが未対応のため、誤ったエンドポイントに通信しており使用できない状況
  • ローカルにプロキシを立てることで、sdkからmock apiへの通信を修正すれば使用できる

動作検証バージョン

"aws-amplify": "^4.3.14"
"next": "^11.1.3"

詳細

mock api はsubscriptionに対応していない?

元々subscriptionが動作しないというバグがあったようだが、修正されているとのことでした。
https://github.com/aws-amplify/amplify-cli/issues/6026

しかしmock apiを動作させると分かりますが、どうもクライアントからの通信先がおかしいです。
aws-sdkの修正状況にずれが生じていることが原因のようです。

issueでは、subscription の mock api 動作時に/graphqlではなく、/graphql/realtimeへアクセスしてしまっていることが問題のため、rewritesなどして向き先を変える必要があるとのことでした。
https://github.com/aws-amplify/amplify-cli/issues/9621

URLの書き換えをするだけなのだが。。

/graphql/realtimeへのアクセスを/graphqlに書き換える(/graphqlへのアクセスはそのままにする)だけで、問題は解決しそうです。

NextJSを使用しているなら、rewritesの設定するだけということでパッとやってみましたが、うまく動作しませんでした。また、rewriteは気軽に使用しない方がいいという記事も発見しました。
https://zenn.dev/catnose99/scraps/91c31ee6609929

そもそも、 テスト環境作るためだけに、rewrite設定なんて入れたくない ため、別の手段を考えることにしました。

nodeモジュールでプロキシを立てる

nginxなど、プロキシアプリを別に設定することも考えましたが、NextJSプロジェクトの中で(node_modulesで)、管理できると便利だと考え、以下のようにカスタマイズしてプロキシを立てることとしました。

プロキシの方針

  • node-http-proxyをベースにする
  • URL書き換えのオプションがなかったのでカスタマイズする
  • package.jsonにコマンド記載してyarn等で起動管理する

node-http-proxyをカスタマイズ

カスタマイズ結果はblueoath-video-ec/node-http-proxyを参照。

pathRewriteオプションを新設して、正規表現でURL書き換えを行います。

lib/http-proxy/common.js
  if (options.pathRewrites && (options.pathRewrites instanceof Array)) {
    for (var i = 0; i < options.pathRewrites.length; i++) {
      console.log(outgoing.path);
      var from = options.pathRewrites[i].from
      var to = options.pathRewrites[i].to
      outgoing.path = outgoing.path.replace(new RegExp(from, 'g'), to);
    }
  }

使い方は以下のような感じです。

proxy.js
var proxy = new httpProxy.createProxyServer({
  ...
  pathRewrite: [
    { from: "^/graphql/realtime", to: "/graphql" }
  ],
  ...
});

package.jsonへの組み込み

まずは、カスタマイズしたライブラリを追加します。
package.jsonに以下のように追加してyarn installを実行します。

package.json
  "devDependencies": {
    ...
    "node-http-proxy": "git+https://github.com/blueoath-video-ec/node-http-proxy.git",
    "kill-port": "^1.6.1",
    ...
  }

yarnを使用していますが、適宜npmなどに読み替えてください。
カスタマイズしたライブラリは適宜自分の環境にforkするなどしてください。

プロジェクトのルートにproxy.jsonを配置して、プロキシサーバの起動コードを記載します。

サンプルコード
proxy.js
// NOTE: カスタマイズしたProxyを使用していることに注意(pathRewrite追加している)
// https://github.com/http-party/node-http-proxy
// https://github.com/blueoath-video-ec/node-http-proxy
var http = require('http');
var httpProxy = require('node-http-proxy');

var mockAPIServerPort = 20002
var proxyPort = 8015

//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.createProxyServer({
  target: {
    protocol: 'http',
    host: 'localhost',
    port: mockAPIServerPort,
    path: '/',
  },
  pathRewrite: [
    { from: "^/graphql/realtime", to: "/graphql" }
  ],
  changeOrigin: true
});
var proxyServer = http.createServer(function (req, res) {
  proxy.web(req, res, function (err) {
    // Now you can get the err
    // and handle it by your self
    // if (err) throw err;
    console.log("http error === ")
    console.log(err);
  });
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
  proxy.ws(req, socket, head, function (err) {
    // Now you can get the err
    // and handle it by your self
    // if (err) throw err;
    console.log("ws error === ")
    console.log(err);
    socket.close();
  })
});

console.log("mockAPIServerPort: " + mockAPIServerPort)
console.log("proxyPort: " + proxyPort)

proxyServer.listen(proxyPort);

mockAPIServerPortは、mock apiサーバのポートです。
proxyPortは、今回作成したプロキシサーバのポートです。

プロキシサーバ起動オプション追加

package.jsonに以下を追記します。

package.json
  "scripts": {
    ...
    "mock:api": "yarn kill-amplify-mock-api && amplify mock api",
    "mock:proxy": "node ./proxy.js",
    "kill-amplify-mock-api": "kill-port 20002 && kill-port 20003"
  },

これでyarn mock:apiと打つと、mockサーバを停止して、プロキシサーバが起動されます。

アプリから使うぞ!

プロキシサーバを立てても、それだけではmock apiを使用できません。
Amplify.configureにおける、aws-exportsの情報を書き換えて、エンドポイントがプロキシサーバに向くように修正が必要です。コンフィグ設定についてはここを参照。

somewhere-in-the-app.tsx
import awsExports from '../aws-exports'

//Amplify.configure({ ...awsExports, ssr: true })
let usingProxy = awsExports
usingProxy.aws_appsync_graphqlEndpoint = 'http://localhost:8015/graphql'
Amplify.configure({ ...usingProxy, ssr: true })

上記の設定は、 ローカルデバッグの時のみ実施 する必要があります。
環境変数等で、コードの有効無効を切り替えてください。

localhost:8015のポートは、proxy.jsで設定したproxyPortの値を設定します。
なお、amplify mock api 実行により、aws-exports.jsの値が自動で書き変わります(mock apiの便利なところ)。

aws-exports.js
const awsmobile = {
    ...
    "aws_appsync_graphqlEndpoint": "http://192.168.12.8:20002/graphql",

上記の:20002はmock api サーバのエンドポイントです。
これを

somewhere-in-the-app.tsx
usingProxy.aws_appsync_graphqlEndpoint = 'http://localhost:8015/graphql'

でプロキシサーバのエンドポイントに上書き変更しています。

まとめ

AWS Amplify mock apiでsubscriptionは動作しますが、一工夫必要です。
Amplify(AppSync)は、subscriptionがあるから使ってるようなものなので、ローカル環境でmock apiが動くととても快適に開発が進められます。多少のモック環境用コードを付与する必要がありますが、やる価値はあると思いますので、ぜひお試しください。

1
0
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
1
0