NestJSを概観する
参考
【2024年最新】NestJS入門 TypeScriptではじめるサーバーサイド開発
NestJSとは
Node.jsサーバーサイドアプリケーションを構築するためのフレームワーク。
JavaScriptでサーバサイドアプリケーションを作成するためのアーキテクチャを提供する、という哲学のもと構成されている。
公式ドキュメントのOverviewには、以下の概念が項目として挙げられている。
- Controllers
- Providers
- Modules
- Middleware
- Exception filters
- Pipes
- Guards
- Interceptors
- Custom Decorator
このうち、Controllers, Providers, Modulesはクライアントからのリクエストに対するルーティングやビジネスロジック、またそれらをまとめる機能を提供する。Middleware, Exception filters, Pipes, Guards, Interceptorsはリクエストとレスポンスの経路上で様々な役割を果たす。
また、Middleware を除く
- Exception filters
- Pipes
- Guards
- Interceptors
について、これらをアプリケーションへと登録する際に、実際には次の四つのレベルがある:
- Global (グローバルなレベル)
- Controller (コントローラのレベル)
- Method (メソッドのレベル)
- Param (パラメータのレベル、これは後述するように Pipe のみ設定可能)
つまり、どのレベルで各機能を使いたいかに応じて、コード内での使用方法も変化する。
Controllers, Providers, Modules
これらはNestJSのアーキテクチャの基本をなす概念であり、このアーキテクチャを図にすると以下のようになる。
Featureはルートモジュールに登録しないと使えない。
Feature実装→ルートモジュール追加という流れ
Moduleとは
ControllerやServiceをまとめ、1つの機能として利用できるセットとして登録する役割を持つもの。
アプリケーションには必ず1つのルートモジュールと0個以上のFeatureモジュールがあるが、コードの整理のためにFeatureモジュールを用いることが強く推奨されている。
定義方法
- クラスに
@Module
デコレーターをつける。 -
@Module
デコレーターの各プロパティを記述する。- providers
DIをするためのプロパティ。@Injectable
デコレーターがついたクラスを記述する。 - controllers
Controllerを使用するためのプロパティ。@Controller
デコレーターがついたクラスを記述する。 - imports
モジュール内部で必要な外部モジュールを記述するためのプロパティ。
Featureモジュールをルートモジュールに追加する場合もここを利用する。 - exports
外部モジュールで利用したいものを記述する。
- providers
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
作成コマンド
nest g module <name>
これを実行することで、Featureモジュールの作成に加えルートモジュールにFeatureモジュールが追加
される。
Controllerとは
クライアントからのリクエストを受け取り、レスポンスを返す役割をもつ。つまり、NestJSにおけるルーティングの機能を担う。
定義方法
- クラスに
@Controller()
デコレータをつける。 - メソッドにHTTPメソッドデコレーターをつける。
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}
作成コマンド
nest g controller <name>
これを実行することで、コントローラーの作成だけでなく関連するFeatureモジュールにコントローラーが登録される。
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController], // Controller の登録
providers: [CatsService],
})
export class CatsModule {}
Serviceとは
Providerの一種で、ひとまとまりの処理。Controllerから呼び出すことで機能を実現する。
Provider
@Injectable() デコレータを適用したクラスで、依存関係として注入(Dependency Injection)される役割を持つ単純なJavaScriptのクラス。
Controllerから複雑なタスクを委任され、代わりに実行することでコードの見通しをよく保つことができる。DIの機能はNestJSのランタイムに委任でき、開発者は、NestJSから渡されたProviderインスタンスを使うだけで目的の機能を使うことができる。
定義方法
- クラスに
@Injectable()
デコレーターをつける。 - メソッドを作成する。
使用方法
- ModuleのprovidersにServiceを登録する。
- ControllerのconstructorでServiceを引数に取る
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
作成コマンド
nest g service <name>
これを実行することで、Serviceが作成されるだけでなく、関連するFeatureモジュールにServiceが登録される。
Pipe
クライアントから送られたリクエストに対し、ハンドラで受け取る前にある処理を施す。
行われる処理は以下の2つ。
- 変換
入力データを希望の形式に変換する(例:文字列から整数へ) - バリデーション
入力データを評価し、有効であればそのまま通過させ、そうでなければ例外を投げる。
イメージとしては以下の通り。
引用:https://docs.nestjs.com/pipes
@Injectable()
デコレーターを適用し、PipeTransform
インターフェースを実装したクラスとして定義されるが、組み込みPipeやclass-validatorなど実装済のものを使用することが多い。
なお、NestJSには9つの組み込みPipeが存在する:
- ValidationPipe
- ParseIntPipe
- ParseFloatPipe
- ParseBoolPipe
- ParseArrayPipe
- ParseUUIDPipe
- ParseEnumPipe
- DefaultValuePipe
- ParseFilePipe
なお、これらは@nestjs/common
から提供される。
適用方法
適用方法が複数ある。
a. ハンドラーへ適用
b. パラメータごとに適用
@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
return this.catsService.findOne(id);
}
c. グローバルへの適用