この記事について
Node.js Express をキャッチアップし、アウトプットしようと簡単なWebアプリを作成したとき、Proxyの設定に少々つまづいたので備忘録。
やりたいこと
- Github APIを利用し、Githubのクローンを作成したい(ユーザー情報閲覧、フォロー、フォロワー、リポジトリ、ユーザー検索機能のみ)。
- ServerサイドでAPIを作成(Node.js Express)。
- ClientサイドはReactで作成。
バージョン
$ node -v
v14.17.0
$ npm -v
6.14.13
express: 4.18.1
react: 18.1.0
想定
- React project ・・・
http://localhost:3000
- Express project ・・・
http://localhost:5000
ユーザーはhttp://localhost:3000
にアクセスすることでReactによって描画されたブラウザを閲覧できる。
アプリケーション内でGithubユーザーの検索や、フォロワー情報の取得などする際は、Express側で取得したGithub APIの情報をclient側へ渡す。
client(React)側から直接外部APIの呼び出しは行わない(通常client側からDBアクセスはしないことを想定)。
app/client/package.json
に"proxy"
Keyを設定し"http://localhost:5000"
をValueとすることでExpressで作成したAPIサーバーへアクセスできる。
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000" // この行を追加
}
処理の流れ
フォロワー一覧取得の場合
- client側から
http://localhost:5000/api/v1/followers
へGETリクエスト。 - server側でGithub API
https://api.github.com/users/{userName}/followers
へGETリクエスト。 - 受けっとったレスポンスを必要な情報のみに整形。
- 結果をclientへ返す。
- Reactでスタイリングし、ブラウザへ描画。
ディレクトリ構成
app
├── client
│ ├── node_modules
│ ├── src
│ │ ├── app
│ │ │ └── App.jsx
│ │ ├── index.css
│ │ └── index.js
│ └── package.json
│
├── node_modules
├── server
│ └── server.js // Express で API 作成
└── package.json
実行
/app/package.json
のコマンドを実行
"scripts": {
"client-install": "cd client && npm install",
"client": "npm start --prefix client",
"server": "nodemon server/server.js",
"dev": "concurrently \"npm run server\" \"npm run client\""
}
$ pwd
/app
$ npm run dev
実行エラー
コンソールエラー
[1] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
[1] - options.allowedHosts[0] should be a non-empty string.
[1] npm ERR! code ELIFECYCLE
[1] npm ERR! errno 1
[1] npm ERR! client@0.1.0 start: `react-scripts start`
npm ERR! Exit status 1
[1] npm ERR!
[1] npm ERR! Failed at the client@0.1.0 start script.
[1] npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
[1]
[1] npm ERR! A complete log of this run can be found in:
[1] npm ERR! /Users/.npm/_logs/2022-05-21T03_09_52_961Z-debug.log
[1] npm ERR! code ELIFECYCLE
[1] npm ERR! errno 1
[1] npm ERR! react-express-api@1.0.0 client: `npm start --prefix client`
[1] npm ERR! Exit status 1
npm ERR!
[1] npm ERR! Failed at the react-express-api@1.0.0 client script.
[1] npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
[1]
[1] npm ERR! A complete log of this run can be found in:
[1] npm ERR! /Users/.npm/_logs/2022-05-21T03_14_06_437Z-debug.log
[1] npm run client exited with code 1
指定されたログファイル
〜〜 省略 〜〜
14 verbose pkgid react-express-api@1.0.0
15 verbose cwd /Users/project/app
16 verbose Darwin 21.4.0
17 verbose argv "/Users/.nodebrew/node/v14.17.0/bin/node" "/Users/.nodebrew/current/bin/npm" "run" "dev"
18 verbose node v14.17.0
19 verbose npm v6.14.13
20 error code ELIFECYCLE
21 error errno 1
22 error react-express-api@1.0.0 dev: `concurrently "npm run server" "npm run client"`
22 error Exit status 1
23 error Failed at the react-express-api@1.0.0 dev script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]
client側のみ立ち上げてみる
$ pwd
/app/client
$ npm run start
コンソールエラー
Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.allowedHosts[0] should be a non-empty string.
When specified, "proxy" in package.json must be a string.
[1] Instead, the type of "proxy" was "object".
[1] Either remove "proxy" from package.json, or make it a string.
昨日までこの設定で動かして開発していたのに、突然動かなくなり頭の中が ???? でした。
解決法
app/client/package.json
に設定した"proxy"
を削除
〜〜 省略 〜〜
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000" // この行を削除
}
新たにhttp-proxy-middleware
というパッケージを追加し、app/client/src/setupProxy.js
というファイルを作成します。
$ pwd
/app/client
$ npm install http-proxy-middleware
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = (app) => {
app.use(
'/api/*',
createProxyMiddleware({
target: 'http://localhost:5000',
changeOrigin: true,
})
);
};
create-react-app
が、自動的にsrc/setupProxy.js
このファイルを探すので、importなどは不要とのこと。
修正後ディレクトリ構成
app
├── client
│ ├── node_modules
│ ├── src
│ │ ├── app
│ │ │ └── App.jsx
│ │ ├── index.css
│ │ ├── index.js
│ │ └── setupProxy.js // 新たに追加
│ └── package.json
│
├── node_modules
├── server
│ └── server.js
└── package.json
動作確認
まずはclient側だけ立ち上げてみる
$ pwd
/app/client
$ npm run start
無事成功!
client側、 server側同時に立ち上げてみる
$ pwd
/app
$ npm run dev
無事成功!!
まとめ
途中にも書きましたが、前日まで動いていたのに、突然動かなくなった理由はわかりません。
しかし、この修正でより安定した開発ができそうです。
原因がわかる方いらっしゃいましたら、ご教授ください。
また、今Webアプリの全貌は別記事にまとめる予定ですので、よろしければそちらもご覧ください。
参考にしたサイト