Dev Study
← 解説「カスタムパイプ — transform の契約」に戻る

サンプルコードで身につける: カスタムパイプ — transform の契約

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1組み込みの ParseIntPipe を使う

前のレッスンで保留にした「@Param は文字列」問題を解決する組み込みパイプの例です。引数単位でパイプを差し込むと、ハンドラに届く時点で値が変換済みになります。変換できなければ自動で 400 が返ります。

import { Controller, Get, Param, ParseIntPipe } from "@nestjs/common";

@Controller("users")
export class UsersController {
  // /users/42  → id は number の 42 になる
  // /users/abc → パイプが弾いて自動で 400 Bad Request
  @Get(":id")
  findOne(@Param("id", ParseIntPipe) id: number) {
    return { id, idType: typeof id }; // "number"
  }
}
// 「@Param は文字列」問題は ParseIntPipe で解決するのが定番

2自作の TrimPipe

前後の空白を取り除いてからハンドラへ渡す自作パイプです。PipeTransform の transform() を実装するだけで組み込みパイプと同列に使える、という「契約を満たせば何でもパイプ」の感覚を掴む例です。

import { Injectable, PipeTransform } from "@nestjs/common";

@Injectable()
export class TrimPipe implements PipeTransform<string, string> {
  transform(value: string): string {
    // 前後の空白を取り除いてからハンドラへ渡す
    return value.trim();
  }
}

// 適用例: 検索キーワードの正規化
// @Get("search")
// search(@Query("keyword", TrimPipe) keyword: string) { ... }
//
// 「値を受け取り、変換して返す」契約を満たせば何でもパイプになる

3既定値を補うパイプを再現

値が未指定のときに既定値を補う、というパイプの発想をプレーン TypeScript で再現した例です。NestJS 組み込みの DefaultValuePipe と同じ仕組みで、「変換」には値の補完も含まれることが分かります。

TypeScript

4値を2択に制限するパイプ

並び順の指定を asc / desc の2択に制限する自作パイプです。変換だけでなく「不正なら例外を投げて弾く」のもパイプの契約の一部であり、ハンドラには検証済みの値しか届かない状態を作れます。

import { Injectable, PipeTransform } from "@nestjs/common";

// 並び順の指定を "asc" / "desc" の2択に制限するパイプ
@Injectable()
export class ParseSortOrderPipe implements PipeTransform<string, string> {
  transform(value: string): string {
    if (value !== "asc" && value !== "desc") {
      // 実際の NestJS では 400 になる専用の例外を投げる
      throw new Error("sort は asc か desc を指定してください");
    }
    return value;
  }
}

// 適用例: @Query("sort", ParseSortOrderPipe) sort: string
// ハンドラに届く時点で「2択のどちらか」であることが保証される

5CSVクエリを配列に変換する

?tags=nestjs,typescript のようなカンマ区切りクエリを配列へ変換する実務パイプです。空白の除去や未指定時の空配列化までパイプ内で済ませることで、ハンドラには正規化済みの配列だけが届きます。

import { Injectable, PipeTransform } from "@nestjs/common";

// GET /articles?tags=nestjs, typescript ,api のような
// カンマ区切り文字列を正規化済みの string[] に変換する
@Injectable()
export class ParseCsvPipe
  implements PipeTransform<string | undefined, string[]>
{
  transform(value: string | undefined): string[] {
    if (value === undefined || value === "") return [];
    return value
      .split(",")
      .map((item) => item.trim())
      .filter((item) => item !== "");
  }
}

// 使う側: @Query("tags", ParseCsvPipe) tags: string[]
// 絞り込み検索 API のタグ・ID リスト受け取りで頻出のパターン