こんにちは、かつコーチです。
Expressでアプリを作り始めると、app.js(またはindex.js)にapp.get()やapp.post()をどんどん書き足していきがちです。
最初は数個だったルートも、機能が増えるにつれて数十行、数百行と膨れ上がっていきます。
この記事では、そんな1ファイルの肥大化を解決するexpress.Router()の使い方を解説します。
ルートをファイル単位で分割し、見通しの良いディレクトリ構成にする方法が身につきます。
Routerとは?
1ファイルにルートを書き続ける問題点
まずは、Routerを使わない場合のコードを見てみましょう。
// ❌ すべてのルートを1つのファイルに書いてしまう例
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users', (req, res) => { /* ユーザー一覧 */ });
app.get('/users/:id', (req, res) => { /* ユーザー詳細 */ });
app.post('/users', (req, res) => { /* ユーザー作成 */ });
app.get('/products', (req, res) => { /* 商品一覧 */ });
app.get('/products/:id', (req, res) => { /* 商品詳細 */ });
app.post('/products', (req, res) => { /* 商品作成 */ });
// ここからさらに注文、レビュー、認証...と続く
app.listen(3000);
この状態が続くと、「ユーザー関連の処理はどこ?」「商品の処理を直したいのに、関係ないコードまで目に入る」といった問題が起きます。
複数人での開発では、同じファイルを同時に編集してコンフリクトが起きやすくなるのも困りものです。
express.Router()の役割
express.Router()は、ルート定義をひとまとまりの「ミニアプリケーション」として切り出すための仕組みです。
機能ごと(ユーザー、商品、注文など)にファイルを分けて、それぞれのファイルでRouterを作成します。
最後にメインのapp.jsから、それぞれのRouterをapp.use()で取り込む(マウントする)ことで、全体を組み立てます。
家に例えると、部屋ごとに設計図を分けて、最後に1つの家として組み上げるようなイメージです。
基本の書き方 / 実装手順
手順1:Routerファイルを作成する
まずは、ユーザー関連のルートをまとめたroutes/users.jsを作成します。
// routes/users.js
const express = require('express');
const router = express.Router();
// ダミーのユーザーデータ
const users = [
{ id: 1, name: '田中太郎' },
{ id: 2, name: '鈴木花子' },
];
// GET /users
router.get('/', (req, res) => {
res.json(users);
});
// GET /users/:id
router.get('/:id', (req, res) => {
const user = users.find((u) => u.id === Number(req.params.id));
if (!user) {
return res.status(404).json({ error: 'ユーザーが見つかりません' });
}
res.json(user);
});
// POST /users
router.post('/', (req, res) => {
const newUser = { id: users.length + 1, name: req.body.name };
users.push(newUser);
res.status(201).json(newUser);
});
module.exports = router;
ポイントは、router.get('/')のようにパスの先頭を/usersではなく/から書き始めることです。
/usersの部分は、次のステップでマウントするときにまとめて指定します。
手順2:同様に商品用のRouterも作成する
// routes/products.js
const express = require('express');
const router = express.Router();
const products = [
{ id: 1, name: 'ノートPC', price: 98000 },
{ id: 2, name: 'マウス', price: 2000 },
];
router.get('/', (req, res) => {
res.json(products);
});
router.get('/:id', (req, res) => {
const product = products.find((p) => p.id === Number(req.params.id));
if (!product) {
return res.status(404).json({ error: '商品が見つかりません' });
}
res.json(product);
});
module.exports = router;
手順3:app.jsでマウントする
最後に、メインのファイルで各Routerを読み込み、app.use()でマウントします。
// app.js
const express = require('express');
const usersRouter = require('./routes/users');
const productsRouter = require('./routes/products');
const app = express();
app.use(express.json());
// /users以下のリクエストは usersRouter に任せる
app.use('/users', usersRouter);
// /products以下のリクエストは productsRouter に任せる
app.use('/products', productsRouter);
app.listen(3000, () => {
console.log('サーバーを起動しました');
});
こうすると、GET /usersにアクセスしたリクエストは、app.use('/users', usersRouter)によってusersRouterに渡されます。
さらにusersRouter内のrouter.get('/')が処理を担当する、という流れになります。
app.jsはマウントの記述だけになるので、全体の見通しが一気に良くなります。
よくあるつまずきポイント・エラー対処
マウントパスとRouter内のパスを混同する
Routerに慣れていない段階でよくあるのが、マウントパスの重複です。
// ❌ Before:Router内にも /users を書いてしまう
// routes/users.js
router.get('/users', (req, res) => {
res.json(users);
});
// app.js
app.use('/users', usersRouter);
このコードだと、実際にアクセスできるURLは/users/usersになってしまいます。
私も最初にRouterを使ったとき、この重複に気づかず「404が出る」と数十分悩んだことがあります。
// ✅ After:Router内は / から書き始める
// routes/users.js
router.get('/', (req, res) => {
res.json(users);
});
// app.js(マウント側でパスを指定する)
app.use('/users', usersRouter);
「マウントパスはapp.js側、Router内は相対パス」というルールを徹底すると、この混乱を防げます。
module.exportsを書き忘れて undefined が渡される
もう1つよくあるミスが、module.exports = router;の書き忘れです。
// ❌ Before:module.exportsを書いていない
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json(users);
});
// module.exportsがない
このファイルをrequireすると、usersRouterは{}(空オブジェクト)になり、app.use('/users', usersRouter)を実行した瞬間に以下のようなエラーが出ます。
TypeError: app.use() requires a middleware function
// ✅ After:ファイルの末尾でexportする
module.exports = router;
このエラーが出たら、まず該当ファイルの末尾にmodule.exportsがあるかを確認してみてください。
まとめ
この記事のポイント
express.Router()を使うと、ルート定義を機能ごとのファイルに分割できる- Router内のパスは相対パス(
/から)で書き、マウントパスはapp.js側で指定する app.use('/マウントパス', router)で、メインアプリにRouterを取り込む- ファイルの末尾で
module.exports = router;を忘れると、app.use()でエラーになる
次に読むべき記事
- ミドルウェアとは?express.json()やカスタムミドルウェアの作り方
- シンプルなREST APIを作る(CRUD実装)
- エラーハンドリングミドルウェアで一元的にエラーを処理する
タグ: Express, 中級者向け, フレームワーク基礎