第6章
Fastifyのエラーハンドリング — 4xxと500を整理して返す
約4分
APIでは、成功よりも失敗の扱いで設計の差が出ます。入力値が間違っている、データが存在しない、権限がない、DBが落ちている。これらをすべて同じ 500 にすると、クライアントも運用者も原因を判断できません。
Fastifyでは、handlerから throw したエラーやschema validationのエラーを、共通のエラーハンドラで整理できます。
まずステータスを分ける
| 状況 | ステータス | 例 |
|---|---|---|
| 入力値が不正 | 400 | title が空 |
| 認証が必要 | 401 | トークンがない |
| 権限がない | 403 | 他人のTodoを編集しようとした |
| 見つからない | 404 | 指定IDのTodoがない |
| 競合 | 409 | 同じ名前が既にある |
| サーバー側の想定外 | 500 | DB接続失敗、バグ |
setErrorHandler() の構文
構文: fastify.setErrorHandler(handler)
| 引数 | 型 | 説明 |
|---|---|---|
handler | function | (error, request, reply) を受け取るエラー処理関数 |
戻り値: Fastifyインスタンス。設定処理として使います。
fastify.setErrorHandler((error, request, reply) => {
request.log.error(error);
return reply.code(500).send({
error: {
code: 'INTERNAL_ERROR',
message: 'サーバーエラーが発生しました',
},
});
});js
バリデーションエラーを整える
schema validationで失敗したエラーには、Fastifyが validation などの情報を付けます。これを使って、入力エラーだけ 400 として返します。
fastify.setErrorHandler((error, request, reply) => {
if (error.validation) {
return reply.code(400).send({
error: {
code: 'VALIDATION_ERROR',
message: '入力値が正しくありません',
details: error.validation,
},
});
}
request.log.error(error);
return reply.code(500).send({
error: {
code: 'INTERNAL_ERROR',
message: 'サーバーエラーが発生しました',
},
});
});js
業務エラーを作る
存在しないTodoを指定された場合は、handler内で404を返しても構いません。ただ、同じエラーが複数箇所に出るなら、専用のエラークラスにすると整理しやすくなります。
class NotFoundError extends Error {
constructor(message = 'Not Found') {
super(message);
this.name = 'NotFoundError';
this.statusCode = 404;
this.code = 'NOT_FOUND';
}
}js
fastify.get('/todos/:id', async (request) => {
const todo = todos.find((item) => item.id === request.params.id);
if (!todo) {
throw new NotFoundError('Todoが見つかりません');
}
return todo;
});js
エラーハンドラ側で statusCode と code を見ます。
fastify.setErrorHandler((error, request, reply) => {
if (error.statusCode && error.statusCode < 500) {
return reply.code(error.statusCode).send({
error: {
code: error.code ?? 'BAD_REQUEST',
message: error.message,
},
});
}
request.log.error(error);
return reply.code(500).send({
error: {
code: 'INTERNAL_ERROR',
message: 'サーバーエラーが発生しました',
},
});
});js
404ハンドラ
存在しないURLにアクセスされた場合は、setNotFoundHandler() で形式を揃えます。
fastify.setNotFoundHandler((request, reply) => {
return reply.code(404).send({
error: {
code: 'ROUTE_NOT_FOUND',
message: '存在しないURLです',
},
});
});js
学習者404ってエラーハンドラだけで拾えないんですか?
先生ルートが見つからない状態は、handler内でthrowされた例外とは別物です。Fastifyではnot found専用のhandlerで整えるのが分かりやすいです。
参考リンク
次章では、ルートや設定を機能単位に分けるためのプラグインを学びます。
Node.jsクイズに挑戦する例外、HTTPステータス、JSONレスポンスの知識をクイズで確認しよう
