はじめに
Node.js の Express を使った API 開発中、エンドポイント /api/jobs/count
にアクセスした際にjobsのカウント数ではなく "Job not found"
というエラーメッセージが返ってくる問題に直面しました。
他のエンドポイント(/api/jobs
, /api/jobs/search
など)は正しく動作している中、なぜか /count
だけが動作しないという状態でした。
問題の状況
1. ルート定義
以下のようなルートを jobRoutes.js
に定義していました。
router.get('/', jobController.getAllJobs);
router.get('/search', jobController.searchJobs);
router.get('/:id', jobController.getJobById);
router.post('/', jobController.createJob);
router.get('/count', jobController.getJobCount); // ここが動かない
2. 動作確認
以下のエンドポイントにアクセスした結果:
-
http://localhost:3000/api/jobs
→ 正常に動作 -
http://localhost:3000/api/jobs/search
→ 正常に動作 -
http://localhost:3000/api/jobs/count
→"Job not found"
原因
ルート定義の順序
Express では、ルートは上から順番に評価されるのが原因でした。
/:id
ルートが /count
よりも先に定義されていたため、/count
が /:id
にマッチしてしまい、getJobById
コントローラーが実行されていたようです。
全然原因に気づかず1時間くらい時間を溶かしてしまいました・・・
解決方法
1. ルートの順序を修正
/count
のルートを /:id
よりも先に定義するように変更しました。
router.get('/count', jobController.getJobCount); // 先に定義
router.get('/', jobController.getAllJobs);
router.get('/search', jobController.searchJobs);
router.get('/:id', jobController.getJobById); // 後に定義
router.post('/', jobController.createJob);
2. コントローラーを確認
getJobCount
コントローラーも確認しましたが、特に問題はありませんでした。
exports.getJobCount = async (req, res) => {
try {
const [rows] = await pool.query('SELECT COUNT(*) AS count FROM jobs');
const jobCount = rows[0]?.count || 0;
res.json({ count: jobCount });
} catch (error) {
console.error('Error fetching job count:', error);
res.status(500).json({ message: 'サーバーエラーが発生しました', error });
}
};
学んだこと
Express のルート定義は順序が重要
- 具体的なパス(例:
/count
)をワイルドカード(例:/:id
)よりも先に定義する必要がある。 - 順序を誤ると、意図しないルートにマッチしてしまう。
まとめ
Node.js と Express を使った開発では、ルートの定義順序が非常に重要になるということがわかりました。特に、具体的なルートとワイルドカードルートが混在する場合、具体的なルートを先に定義することで意図しない動作を防ぐことができます。