NestJSのエラーレスポンスをカスタマイズする

NestJSを用いAPI作成をしているのだが、Responseを共通化したいと思ったので、実装してみた。

目次

NestJSを用いAPI作成をしているのだが、Responseを共通化したいと思ったので、実装してみた。

Responseの定石

とは言えそもそもResponseの形をどのようにするのがいいのかわからなかったので調べた結果、omniti-labs/jsendが参考になりそうだった。
これを参考に以下のような型で返すことにした。

export interface Response {
  status: 'success' | 'error';
  data: any;
  message: string[] | null;
}

ValidationPipeを使用する場合、エラーレスポンスの形式はBadRequestExceptionがデフォルト

たぶんドキュメントにある通り(Documentation | NestJS – A progressive Node.js framework)なので、ほとんどの場合ValidationPipeを使用することになる。
そうするとエラーレスポンスの形式はBadRequestExceptionがデフォルトになるので、以下のように返ってくる。

{
  "statusCode": 400,
  "message": "Bad Request Exception",
  "error": "Bad Request"
}

これは意図した形ではないのでカスタマイズする必要がある。

http-exception.filter.tsを作成する

カスタマイズするにはそれ用のException filtersを用意する必要がある。
Exception filtersとは、

Nestには例外処理レイヤーが組み込まれており、アプリケーション全体で処理されない例外をすべて処理する責任を負っています。アプリケーションのコードで処理できない例外は、このレイヤーでキャッチされ、適切なユーザーフレンドリーな応答が自動的に送信されます。

というものらしい。

とにかく例外フィルターは、NestJSアプリケーションが例外をキャッチした場合に呼び出されるらしい。

実装は簡単

まずはhttp-exception.filter.tsを作成する。

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common';
import { Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const status = exception.getStatus();

    response.status(status).json({
      status: 'error',
      data: null,
      message: (exception.getResponse() as any).message || [
        '何らかのエラーが発生しました。',
      ],
    });
  }
}

それをmain.tsで読み込むだけで、

   app.useGlobalPipes(new ValidationPipe());
+  app.useGlobalFilters(new HttpExceptionFilter());

エラーレスポンスが期待した形になって返却されるようになった。

余談

これを実装するときに脳死でChatGPTに質問したところ、いくら質問してもうまく実装できず、ドキュメントを見たら即解決した。
馬鹿と鋏は使いようということで。

次に読むおすすめ記事

NestJsとMySQLでCRUD操作を行ってみた

NestJSでOpenAPIツール「swagger」を生成する

NestJSとclass-validatorでPOST時に検証をする

Windows11に入れたMySQLとNest.Jsを接続し、テーブルを作成する

NestJsにおけるMigrationと「synchronize: true」を調べてみた

この記事に対するコメント

お気軽にコメントを下さい

メールアドレスが公開されることはありません。 が付いている欄は必須項目です