🌮

NestJS/GraphQLのバリデーションエラーが起こった時、エラーメッセージとキーを返したい!

2022/05/23に公開

きっかけ

NestJS/GraphQLのバリデーションエラーが起こった時、デフォルトだとこんなレスポンスになると思います。

request
{
  "input": {
    "name": "",
    "gender": ""
  }
}
response
{
  "errors": [
    {
      "message": "Bad Request Exception",
      "extensions": {
        "code": "BAD_USER_INPUT",
        "response": {
          "statusCode": 400,
          "message": [
            "name should not be empty",
            "email must be an email",
            "email should not be empty"
          ],
          "error": "Bad Request"
        }
      }
    }
  ],
  "data": null
}

ただ、この形だとどの値に対してエラーが起こってるか判別するのに、エラーメッセージの中身を見ないとわかりません...
なので、フロント側の人が使いやすいようにエラーが起こったキーも返す必要がありました。

解決策

NestJSのオプションにexceptionFactoryという例外周りの処理をしてくれそうなのがあったのでこれを使っていきます。

export interface ValidationPipeOptions extends ValidatorOptions {
  transform?: boolean;
  disableErrorMessages?: boolean;
  exceptionFactory?: (errors: ValidationError[]) => any;
}

ValidationPipeの登録時、exceptionFactoryを定義してあげるだけですᕦ(ò_óˇ)ᕤ

 app.useGlobalPipes(
    new ValidationPipe({
      // バリデーションエラーの型を整形する
      exceptionFactory: (errors): ValidationError[] => {
        const messages = errors.flatMap((e) => {
          const res: { key: string; messages: string[] }[] = [];
          const cons = e.constraints ?? {};
          const mes: string[] = [];
          Object.keys(cons).forEach((key) => {
            mes.push(cons[key]);
          });
          res.push({ key: e.property, messages: mes });

          return res;
        });
        throw new BadRequestException(messages);
      },
    }),
  );  
ちなみにerrorsの中身はこんな形になってます
[
  ValidationError {
    target: StudentInput { name: '', email: '' },
    value: '',
    property: 'name',
    children: [],
    constraints: { isNotEmpty: 'name should not be empty' }
  },
  ValidationError {
    target: StudentInput { name: '', email: '' },
    value: '',
    property: 'email',
    children: [],
    constraints: {
      isEmail: 'email must be an email',
      isNotEmpty: 'email should not be empty'
    }
  }
]

レスポンスはこんな感じです。

response
{
  "errors": [
    {
      "message": "Bad Request Exception",
      "extensions": {
        "code": "BAD_USER_INPUT",
        "response": {
          "statusCode": 400,
          "message": [
            {
              "key": "name",
              "messages": [
                "name should not be empty"
              ]
            },
            {
              "key": "email",
              "messages": [
                "email must be an email",
                "email should not be empty"
              ]
            }
          ],
          "error": "Bad Request"
        }
      }
    }
  ],
  "data": null
}

まとめ

これでどの部分でバリデーションエラーになったのか明確にになりました。
めでたしめでたし(╹◡╹)

参考サイト

NestJS公式
https://docs.nestjs.com/techniques/validation

Discussion