NestJSとPostgreSQLで作る本格的なREST API:ゼロからバリデーションまで

Development tutorial - IT technology blog
Development tutorial - IT technology blog

なぜExpressではなくNestJSを使うのか?

Node.jsに慣れているなら、まずExpressが思い浮かぶでしょう。Expressは「改造バイク」のようなものです。何でも自由に取り付けられ、創造性を発揮できます。しかし、プロジェクトが大きくなるにつれ、規律がなければその自由は巨大なゴミの山へと変わってしまいます。私はかつて、純粋なExpressで書かれたスタートアップの5万行のコードベースをリファクタリングしたことがあります。

それはまさに悪夢でした。開発者ごとに書き方が異なり、ロジックはControllerからMiddlewareまでバラバラに散らばっていました。時には、たった一つの小さなロジックエラーを見つけるのに4時間もかかることがありました。

NestJSはこの問題を解決するために登場しました。Node.jsをゼロから学び直す必要はありません。その代わりに、TypeScriptに基づいた非常に厳格なフレームワークを提供します。Expressが「自由市場」なら、NestJSは「計画的に配置されたスーパーマーケット」です。Module、ControllerからServiceに至るまで、すべてに明確な場所があります。

NestJSを実際のプロジェクトに導入する際のメリットとデメリット

NestJSに「乗り換える」決心をする前に、現実を直視する必要があります。完璧な技術など存在しません。あるのは、目的に適した技術かどうかだけです。

メリット:

  • モジュールアーキテクチャ: プロジェクトを独立したパーツに分割します。スケーリングが非常に容易になります。
  • 依存性の注入 (DI): この機能により、ユニットテストの作成が非常に楽になります。わずか数行のコードでデータをモック化できます。
  • 優れたドキュメント: NestJSのドキュメントはトップクラスです。遭遇するほぼすべてのエラーに対する回答がStack Overflowに見つかります。
  • 手厚いサポート: GraphQL、WebSocketsからマイクロサービスまで、NestJSには統合ライブラリが用意されています。

デメリット:

  • 初期の学習コスト: デコレータ(@Controller, @Injectable)やDIの概念に慣れるまで、最初の1〜2週間はかかるでしょう。
  • メモリ消費量: 多くの抽象化レイヤーを含むため、NestJSの新規インスタンスは約60〜80MBのメモリを消費します。Expressの約30MBと比較すると多いですが、現代のサーバーにとっては微々たる差です。

高精度が求められるシステムでのPostgreSQLの選択

なぜMongoDBではなくPostgreSQLなのか?電子マネーの残高や在庫管理など、絶対的な正確性が求められるシステムを扱う場合、私は常にPostgreSQLを選択します。その一貫性(ACID特性)は、NoSQLデータベースが追いつくのが難しい部分です。

NestJSはコード構造に優れ、PostgreSQLはデータ構造に優れています。これらを組み合わせることで、盤石な基盤を構築できます。私の経験から言えば、後で無意味な残業(OT)を避けるために、初日からアーキテクチャに投資すべきです。

構築を始めよう:ステップバイステップの実装

まず、Node.jsとPostgreSQLをインストールしましょう。Dockerを使えば、わずか30秒でデータベースを立ち上げることができます。

1. プロジェクトの初期化

Nest CLIを使用して、ボイラープレートを素早く作成します。

npm i -g @nestjs/cli
nest new my-api-project

好みで npm または yarn を選択してください。数分後には、整理されたフォルダ構造が完成します。

2. PostgreSQLデータベースへの接続

データベースをオブジェクトとして操作するためにTypeORMを使用します。以下のパッケージをインストールしてください。

npm install --save @nestjs/typeorm typeorm pg

src/app.module.ts ファイルを開き、接続設定を入力します:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'postgres',
      password: 'yourpassword',
      database: 'test_db',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true, // 注意:開発時のみ使用。本番環境では絶対に使用しないでください! 
    }),
  ],
})
export class AppModule {}

3. 「Posts」リソースを瞬時に作成

各ファイルを個別に作成する代わりに、CLIに任せましょう:

nest generate resource posts

このコマンドにより、ボイラープレートコードを書く時間を少なくとも15分は節約できます。Controller、Service、DTOが自動的に作成されます。

4. バリデーションで不正なデータを阻止する

これが重要なステップです。クライアントからのデータを決して信用してはいけません。長い if/else 文を書く代わりに、 class-validator を使用しましょう。

npm install --save class-validator class-transformer

main.ts でこの機能を有効にします:

app.useGlobalPipes(new ValidationPipe());

次に、DTOファイルでバリデーションルールを定義します:

import { IsString, MinLength, IsNotEmpty } from 'class-validator';

export class CreatePostDto {
  @IsNotEmpty({ message: 'タイトルは必須入力です' })
  @IsString()
  @MinLength(10, { message: 'タイトルは10文字以上で入力してください' })
  title: string;

  @IsNotEmpty()
  content: string;
}

結果はどうなるでしょうか?クライアントが不足したデータを送信した場合、APIは自動的に詳細なエラーメッセージとともに400エラーを返します。Controller内にエラーチェックのロジックを1行も追加する必要はありません。

おわりに

システムの構築は難しくありません。規模が大きくなったときに清潔さを保つことこそが挑戦です。NestJSとPostgreSQLは、プロフェッショナルなバックエンドキャリアを始めるための完璧なコンビです。アーキテクチャの学習に時間を費やすことを惜しまないでください。それは将来、複雑なコードの山からあなたを救ってくれるでしょう。

実際のプロジェクトでぜひ試してみてください。コードはより洗練され、メンテナンスもずっと容易になるはずです。セットアップでエラーが発生した場合は、下のコメント欄に記入してください!

Share: