api-framework-express について
Express.jsでREST APIを構築する開発者向けのスキルです。モジュール式ルーティング、集中エラー処理、リクエスト検証に加え、Express 4と5の違いを扱います。
主な機能
- 01ミドルウェアチェーンの設定
- 02express.Router()によるモジュール式ルーティング
- 03集中エラー処理
- 04Express 4・5の非同期エラー転送
- 05リクエスト検証とルートガード
- 06ミドルウェア順序とレスポンスヘルパー
活用シーン
- 01リソース別のAPIエンドポイント整理
- 02各ルートのエラー処理の統一
- 03リクエスト検証とルート保護
- 04Expressのバージョンに応じた非同期処理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-framework-expressインストール後、Claude Code で/api-framework-expressを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/core.mdmiddleware.mdrouting.md詳細
Express.js を使った API 開発
クイックガイド: Express はミドルウェアベースのリクエスト処理を使用します。必須のパターンは 3 つです。
express.Router()によるモジュール化されたルーティング、4 引数のミドルウェア(err, req, res, next)による一元的なエラー処理、そして正しいミドルウェアの順序(セキュリティを最初に、エラーハンドラーを最後に)です。Express 5(現在は安定版で、npm のデフォルトです)は非同期エラーを自動的に転送します。Express 4 では、手動でnext(err)を呼び出すか、ラッパーを使用する必要があります。
<critical_requirements>
重要:このスキルを使用する前に
(エラーハンドリングミドルウェアは、必ず 4 つの引数 (err, req, res, next) で定義してください。Express は引数の数でエラーハンドラーを識別します)
(エラーハンドラーは、すべてのルートとその他のミドルウェアの後に必ず登録してください)
(Express 4 では、非同期エラーを転送するために必ず next(err) を呼び出してください。Express 5 は拒否された Promise を自動的に転送します)
(ボディ解析には必ず express.json() と express.urlencoded() を使用してください。これらがないと req.body は未定義です)
</critical_requirements>
自動検出: Express.js、express、app.use、app.get、app.post、app.put、app.delete、express.Router、req.params、req.query、req.body、res.json、res.status、middleware、next()、error handler、router.use、express.static、express.json、express.urlencoded
使用する場合:
- 合成可能なミドルウェアパターンで REST API を構築する場合
express.Router()を使ったモジュール化されたルート構成が必要な場合- すべてのルートで一元的なエラー処理が必要な場合
- ボディ解析、静的ファイル、または Cookie 処理が必要な API を構築する場合
- 認証/認可用のルートガードを作成する場合
使用しない場合:
- スキーマから OpenAPI ドキュメントを自動生成する必要がある場合
- コールドスタートが重要となるエッジ/サーバーレス関数を構築する場合
- スキーマ検証を伴う厳密なエンドツーエンドの型安全性が必要な場合
- GraphQL API を構築する場合(専用の GraphQL サーバーを使用してください)
対象となる主なパターン:
app.use()とnext()によるミドルウェアチェーンexpress.Router()によるモジュール化されたルート- 4 引数のミドルウェアによるエラー処理
- 非同期エラーの転送(Express 4 と 5 の違い)
- リクエスト検証ミドルウェア
- ルートパラメーターとクエリ文字列の処理
- 認証/認可用のルートガード
- ミドルウェアの順序(セキュリティ、CORS、レート制限、解析、ルート、エラー)
詳細なリソース:
- examples/core.md - アプリのセットアップ、エラーハンドラー、非同期ハンドラー、ボディ解析
- examples/middleware.md - ロギング、検証、認証ガード、ミドルウェアの順序
- examples/routing.md - モジュール化されたルート、パラメーター、レスポンスヘルパー、バージョン管理された API
- reference.md - 選択の指針、アンチパターン、本番環境向けチェックリスト
考え方
ミドルウェアを中心とするアーキテクチャ。 Express はミドルウェア関数のチェーンを通じてリクエストを処理します。各ミドルウェアはリクエスト/レスポンスオブジェクトを変更したり、レスポンスを終了したり、next() を呼び出してチェーンを続行したりできます。Express ではすべてがミドルウェアです。ボディパーサー、認証ガード、ロガー、エラーハンドラーなどが該当します。
Express 4 と 5 の違い: Express 5(2025 年から安定版で、現在は npm のデフォルトです)は、非同期ハンドラー内で拒否された Promise から発生するエラーを自動的に転送します。Express 4 では、明示的な try/catch と next(err)、またはラッパーユーティリティが必要です。どちらのバージョンでも、エラーハンドラーには 4 引数のシグネチャが必要です。
基本パターン
パターン 1:アプリケーションのセットアップ
ボディパーサーを早い段階で登録し、ルートモジュールをマウントしてから、最後にエラーハンドラーを登録します。完全な実装については、examples/core.md を参照してください。
const app: Express = express();
// Body parsing
app.use(express.json({ limit: JSON_LIMIT }));
app.use(express.urlencoded({ extended: true }));
// Mount route modules
app.use("/api/users", userRoutes);
app.use("/api/products", productRoutes);
// Error handler MUST be last
app.use(errorHandler);
export { app };
この方法が適切な理由: req.body に値が設定されるよう、ボディパーサーをルートより前に配置します。すべてのエラーを捕捉できるよう、エラーハンドラーを最後に配置します。また、ルートをモジュール単位でマウントできます。
パターン 2:express.Router() によるモジュール化されたルート
リソースごとに 1 つの Router を作成し、パスプレフィックスにマウントします。パラメーターを使った CRUD の例については、examples/routing.md を参照してください。
// src/routes/user-routes.ts
const router = Router();
router.get("/", async (req, res, next) => {
try {
const users = await getUsersFromDatabase();
res.status(HTTP_OK).json({ data: users });
} catch (error) {
next(error);
}
});
export { router as userRoutes };
この方法が適切な理由: Router によって関連するルートを分離し、名前付きエクスポートを使い、エラーを明示的に転送できます。
パターン 3:エラーハンドリングミドルウェア(4 引数)
Express は、4 引数のシグネチャ (err, req, res, next) によってエラーハンドラーを識別します。これは正しく実装することが最も重要な Express パターンです。完全な実装については、examples/core.md を参照してください。
// CRITICAL: Must have exactly 4 arguments
const errorHandler = (
err: AppError,
req: Request,
res: Response,
next: NextFunction,
): void => {
if (res.headersSent) {
next(err);
return;
}
const statusCode = err.statusCode || HTTP_INTERNAL_ERROR;
res.status(statusCode).json({
error: { message: err.message, code: err.code || "INTERNAL_ERROR" },
});
};
優れている点: Express がエラーハンドラーとして認識するための 4 つの引数を備え、二重応答を避けるために headersSent を確認し、一貫したエラー形式を使用しています。
よくある間違い: 3 引数の関数 (err, req, res) は通常のミドルウェアとして扱われます。err が req になり、完全に誤った動作になります。
パターン 4:非同期エラーの処理
Express 5 は、拒否された Promise を自動的に転送します。Express 4 では明示的な転送が必要です。asyncHandler ラッパーについては、examples/core.md を参照してください。
// Express 5: async errors auto-forwarded
router.get("/:id", async (req, res) => {
const product = await getProductById(req.params.id);
res.status(HTTP_OK).json({ data: product });
});
// Express 4: MUST forward manually
router.get("/:id", async (req, res, next) => {
try {
const product = await getProductById(req.params.id);
res.status(HTTP_OK).json({ data: product });
} catch (error) {
next(error); // Required in Express 4
}
});
重要な理由: Express 4 では、未処理の非同期拒否が発生すると、タイムアウトまでリクエストが停止します。Express 5 ではこの問題が修正されていますが、現在も多くのプロジェクトが Express 4 を使用しています。
パターン 5:リクエスト検証ミドルウェア
ルートハンドラーが処理する前に、ミドルウェアで req.body を検証します。検証パターンの全容については、examples/middleware.md を参照してください。
const validateUserCreate = (
req: Request,
res: Response,
next: NextFunction,
): void => {
const { name, email } = req.body;
const errors: string[] = [];
if (!name || name.length < MIN_NAME_LENGTH) errors.push("Name is required");
if (!email || !email.includes("@")) errors.push("Valid email is required");
if (errors.length > 0) {
res
.status(HTTP_BAD_REQUEST)
.json({ error: { message: "Validation failed", details: errors } });
return;
}
next();
};
// Apply: router.post("/", validateUserCreate, createHandler);
優れている点: 検証をビジネスロジックから分離し、失敗時には早期にリターンし、複数のルートで再利用できます。
パターン 6:ルートガード(認証/認可)
アクセスを検証するミドルウェアでルートを保護します。認証ガードの完全な実装については、examples/middleware.md を参照してください。
// Extend Request with user data
interface AuthenticatedRequest extends Request {
user?: { id: string; role: string };
}
const requireAuth = (
req: AuthenticatedRequest,
res: Response,
next: NextFunction,
): void => {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) {
res
.status(HTTP_UNAUTHORIZED)
.json({ error: { message: "Authentication required" } });
return;
}
req.user = verifyToken(token);
next();
};
// Apply to all routes in router: router.use(requireAuth);
// Apply to specific route: router.delete("/:id", requireAuth, requireRole("admin"), handler);
優れている点: 認証ミドルウェアを再利用でき、ロールガードを設定可能で、型安全性のために Request 型を拡張しています。
パターン 7:ミドルウェアの順序
順序が重要です。セキュリティを最初に、エラーハンドラーを最後に配置します。順序の完全な例については、examples/middleware.md を参照してください。
1. Security headers (helmet)
2. CORS
3. Rate limiting (before body parsing to save resources)
4. Body parsing (express.json, express.urlencoded)
5. Request logging
6. Routes
7. 404 handler (after all routes)
8. Error handler (LAST)
この順序にする理由: セキュリティミドルウェアは、不正なリクエストを早期に拒否します。レート制限をパースより前に行うことで、悪意のあるリクエストによる CPU の消費を抑えられます。ルートで発生したすべてのエラーを捕捉するには、エラーハンドラーを最後に配置する必要があります。
パターン 8:レスポンスヘルパー
型付きヘルパーで API レスポンスを標準化します。完全な実装については、examples/routing.md を参照してください。
const sendSuccess = <T>(res: Response, data: T, statusCode = HTTP_OK): void => {
res.status(statusCode).json({ success: true, data });
};
const sendNotFound = (res: Response, resource = "Resource"): void => {
res
.status(HTTP_NOT_FOUND)
.json({ success: false, error: { message: `${resource} not found` } });
};
優れている点: すべてのルートでレスポンス形式を統一でき、型付きヘルパーによって定型コードを減らせます。
Express 5 への移行に関する注意事項
Express 5 は 2025 年 3 月以降、npm のデフォルトです。Express 4 からの主な変更点は次のとおりです。
| 変更点 | Express 4 | Express 5 |
|---|---|---|
| 非同期エラー | 手動で next(err) | 自動転送 |
req.body(未パース) | {} | undefined |
req.query | 書き込み可能 | 読み取り専用のゲッター |
| ワイルドカードルート | /* | /*splat(ルートなし)または /{*splat}(ルートあり) |
| オプションのパラメーター | /:file.:ext? | /:file{.:ext} |
urlencoded のデフォルト | extended: true | extended: false |
req.host | ポートを除外 | ポートを含む |
| 最低 Node.js バージョン | 任意 | 18+ |
Express 5 で削除されたもの: req.param()、res.send(body, status)、res.send(status)(res.sendStatus() を使用)、res.json(obj, status)、res.redirect(url, status)、res.redirect('back')(req.get('Referrer') || '/' を使用)、res.sendfile()(res.sendFile() を使用)、app.del()(app.delete() を使用)。
<red_flags>
危険な兆候
優先度:高
- エラーハンドラーの引数が3つだけ - Express は通常のミドルウェアとして扱うため、エラーが黙って無視されます
- ルートより前にエラーハンドラーを登録している - ルートのエラーを捕捉できません
- 非同期ハンドラーで
next(error)を呼び出していない(Express 4) - 未処理の Promise 拒否が発生し、リクエストが停止します express.json()ミドルウェアを使用していない - JSON リクエストではreq.bodyがundefinedになります- HTTP ステータスコードを直接指定している - 名前付き定数(
HTTP_OK = 200、HTTP_NOT_FOUND = 404)を使用してください
優先度:中
- すべてのルートが単一ファイルにある - 保守が困難な巨大ファイルになるため、
express.Router()を使用してください - エラーハンドラーで
res.headersSentを確認していない - 「headers already sent」エラーによるクラッシュが発生します - ルートモジュールでデフォルトエクスポートを使用している - プロジェクトの規約に違反します
- 認証情報を使用する CORS でワイルドカードを指定している - ブラウザーは
credentials: trueのときorigin: "*"を拒否します - 公開 API にレート制限を設けていない - 悪用されるおそれがあります
注意点とエッジケース:
next('route')とnext(error)の違い - 文字列の'route'は次のルートハンドラーにスキップし、それ以外はエラーハンドラーを呼び出しますreq.queryの値は常に文字列です - 数値はparseInt(val, 10)で解析してください- 認証のない
express.static- ミドルウェアで保護しない限り、ファイルに誰でもアクセスできます - ルーターの
mergeParams: true- ネストされたルーターで親ルートのパラメーターにアクセスするには必須です - Express 5:解析されていない場合、
req.bodyはundefinedです - Express 4 では{}だったため、if (!req.body)のチェックが壊れる可能性があります
</red_flags>
<critical_reminders>
重要な注意事項
Express のルートを実装する前に、以下の要件が満たされていることを必ず確認してください。
(4つの引数 (err, req, res, next) を持つエラーハンドリングミドルウェアを必ず定義してください。Express は引数の数によってエラーハンドラーを識別します)
(すべてのルートとその他のミドルウェアを登録した後に、エラーハンドラーを必ず登録してください)
(Express 4 で非同期エラーを転送するには、必ず next(err) を呼び出してください。Express 5 は拒否された Promise を自動的に転送します)
(リクエストボディを解析するには、必ず express.json() と express.urlencoded() を使用してください。これらがない場合、req.body は undefined になります)
これらのルールに従わないと、エラーが未処理になり、ミドルウェアの連鎖が破損します。
</critical_reminders>