TL;DR

Node.js 上で動くサーバーサイドのフレームワーク。TypeScript で実装されているので TypeScript と相性が良いが、JavaScript でも書ける。

なぜ必要か

TypeScript の型の恩恵を受けられる。内部では標準で Express を使うので、その豊富なライブラリを利用でき、Fastify に切り替えることもできる。Nest CLI でプロジェクトやファイルのテンプレートを作れ、テスト用のフレームワークも標準で用意されている。RDB、NoSQL、GraphQL、WebSocket などにも対応している。

仕組み

アーキテクチャは Angular に大きく影響を受けている。Module、Controller、Service の 3 つを組み合わせて 1 つの機能を実装する。

Module

関連する Controller や Service をまとめて NestJS に登録する。アプリケーションには、すべての Feature module を登録する Root module(app.module.ts)が 1 つ以上と、機能ごとの Feature module が 0 個以上必要である。クラスに @Module デコレータを付け、imports、exports、providers、controllers を書いて定義する。nest g module コマンドでも生成できる。

Controller

クライアントからリクエストを受け取り、レスポンスを返す。GraphQL の場合は Resolver がこの役割を担う。

Service

アプリケーション固有のビジネスロジックを定義し、Resolver や Controller から呼び出してユースケースを実現する。責務ごとに分けることで、保守しやすく拡張しやすくなる(単一責任の原則)。クラスに @Injectable デコレータを付けて定義する。

依存性の注入

NestJS は DI コンテナを提供しているので、依存性の注入を手で書く必要はない。Module の providers に依存される側のクラスを登録し、依存する側のコンストラクタの引数でそのクラスを受け取ればよい。

例

Module と Resolver で、Service を注入する例である。

@Module({
  imports: [PrismaModule],
  providers: [TaskResolver, TaskService],
})
export class TaskModule {}
 
@Resolver()
export class TaskResolver {
  constructor(private readonly taskService: TaskService) {}
 
  // ...
}

CORS を有効にするには、アプリケーションのオブジェクトで enableCors メソッドを呼ぶ。

const app = await NestFactory.create(AppModule)
app.enableCors()

Prisma ORM を使う例は、公式ドキュメントに載っている。

// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit } from "@nestjs/common"
import { PrismaClient } from "@prisma/client"
 
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect()
  }
}
// src/prisma/prisma.module.ts
import { Module } from "@nestjs/common"
import { PrismaService } from "./prisma.service"
 
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

自分の理解

NestJS の公式ドキュメントにある Prisma のレシピは、Service を生成するあたりから読むと参考になる。

関連

出典