キカガク プラットフォームブログ

株式会社キカガクのプラットフォームブログです。エンジニアやデザイナー、プロダクトマネージャーなどが記事を書いています。

NestJS のバリデーションや Pipes のあれこれ

こんにちは、キカガクでソフトウェアエンジニアをしている北田です。

今回は弊社プロダクトでも一部使用しているサーバーサイドフレームワークの NestJS について、Pipes や Validations に焦点を当てて公式ドキュメントの内容ベースで紹介していきます。

これから NestJS を使ってサーバーサイドを実装していく方やサーバーサイド言語のモダンなバリデーションについて興味がある方の参考になれば幸いです。

NestJS のリクエストバリデーション

NestJSでは、コントローラーを介してクライアントサイドから渡されるリクエストオブジェクトやパラメータのバリデーションや変換を簡単に実装することができます。

それらの機能を使用する場合、NestJS にある便利な Pipes を使うことで実現することができます。(公式ドキュメント

Pipes について

Pipes には主に2つの役割があります。

  • リクエストデータの変換
  • リクエストデータの検証(バリデーション)

Pipes をうまく活用することで、リクエストデータがアプリケーションの内部で処理される前に適切な形式や型に従っていることを保証することができます。

実装例

例えば、TODO アプリで新規のタスクを作成する際に、いつまでに完了させるかを設定することができるケースを考えてみましょう。

リクエストデータの中にタスク完了予定日の日付を渡す際に、Date オブジェクトは HTTP リクエストを通じてすべて文字列に変換されてしまいます。

アプリケーションサービス層で変換処理を書いたり libs に変換用のメソッドを用意しておいて… とすることもできますが、Pipes の transform を使って Controller に処理が渡される前に事前に正しい形式に変換するカスタム Pipes を定義することができます。

以下は簡単な実装例です

import type { PipeTransform } from '@nestjs/common';
import { BadRequestException } from '@nestjs/common';
import { ZodSchema } from 'zod';

export class CreateTodoPipe implements PipeTransform {
  transform(value, metadata) {
    constructor(schema: ZodSchema) {}
    try {
      const body = { ...value };
      if (typeof body.taskFinishAt === 'string') {
        body.taskFinishAt = new Date(body.taskFinishAt);
      }
      const parsedValue = this.schema.parse(body);
      return parsedValue;
    } catch (error) {
      throw new BadRequestException('Validation failed while tranforming');
    }
  }
}

あとはこのカスタム Pipes を Controller で @UsePipes()でデコレーターを使って呼び出してあげれば Controller にリクエストが渡ってくるタイミングで変換することができます。

@Post('tasks/:id')
@ApiOperation({ summary: '新規タスクを作成する' })
@UsePipes(new CreateTodoPipe(createTaskSchema))
async createTask(
  @Body()
  body: CreateTaskDto,
) {...}

また、Zod や class-validator を使って、リクエストデータの検証も簡単に実装することができます。

export const createTaskSchema = z.object({
  title: z.string().min(5),
  description: z.string(10),
  taskFinishAt: z.date(),
})

export type CreateTaskDtoDto = Readonly<z.infer<typeof createTaskSchema>>;

先ほど @UsePipes() を使ってセットした Pipes の引数にスキーマを渡してあげるだけで検証が可能になります。

zod を使用する場合、リクエストに含まれるフィールが適切ではないことが検証された場合、ZodError に従ってエラーをスローすることになります。

ZodError や ZodIssue インスタンスについてはパッケージの実装をご覧ください。

github.com

テスト

Validation Pipes の変換や検証が正しく行われるかをテストすることも可能です。

github.com

このアプローチにより、データの整合性を保ちながら、アプリケーションの安定性と信頼性を高めることができます。

最後に

以上のように、NestJS を使ってリクエストデータの変換や検証がとても柔軟に、また楽に実装することができます。

キカガクのサービスでも積極的に活用しています。また、今後も NestJS の機能についてメンバー間で技術共有できる体制を整えていきます。

キカガクでは NestJS だけでなく、GraphQL や Prisma, Next.js など様々な技術を活用してプロダクト開発をしています!

ご興味があれば一度カジュアル面談でざっくばらんにお話ししましょう。