Nest.js × Swagger | バリデーターでAPISpecの生成を自動化する
Nest.jsはFatだ!
でもリクエストバリデーションやAPISpec生成をいい感じに巻き取ってくれるから使います。
もちろんFastifyでも実現できるのですが、今回はお手軽なNest.jsでの手順をメモします。
パッケージをインストール
❯ yarn add -D class-validator class-transformer
グローバルバリデーターを有効化
+ import { ValidationPipe } from '@nestjs/common'
;(async () => {
const app = await NestFactory.create(AppModule)
+ //追加(すべてのエンドポイントが不正なデータを受信しないように保護)
+ app.useGlobalPipes(new ValidationPipe())
await app.listen(3000)
})()
バリデーション用のDTOを作成
+ import { IsNotEmpty, IsOptional, IsNumber, IsString, IsDate } from 'class-validator';
+
+ // このDTOを使用するすべてのルートで、自動的にこのバリデーションルールが適用されるようになる
+ export class CreateSampleDto {
+ @IsNotEmpty()
+ @IsString()
+ name: string;
+
+ @IsNotEmpty()
+ @IsNumber()
+ age: number;
+
+ @IsOptional()
+ @IsDate()
+ birthday?: Date;
+ }
エンドポイントでDTOを使用する
@Controller('sample')
export class SampleController {
+ @Post()
+ create(@Body() createSampleDto: CreateSampleDto) {
+ return createSampleDto
+ }
}
検証
# 起動
❯ yarn start:dev
# 正しいリクエスト
❯ curl -X POST localhost:3000/sample -H "Content-Type: application/json" -d '{"name":"miramira", "age":22}'
{"name":"mirai","age":22}
# 不正なリクエスト
❯ curl -X POST localhost:3000/sample -H "Content-Type: application/json" -d '{"name":"miramira", "age":"HI MI TSU"}'
{"statusCode":400,"message":["age must be a number conforming to the specified constraints"],"error":"Bad Request"}
🎉 無事、不正なリクエストに対して400を返してくれるようになりました!
Swaggerと連携する
現在SwaggerUIはこんな表示になっています。
簡単な設定でバリデーションの情報をSwaggerに再利用します。
@ApiProperty()
デコレーターを追加する
これだけですw
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsDate, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator';
export class CreateSampleDto {
+ @ApiProperty()
@IsNotEmpty()
@IsString()
name: string;
+ @ApiProperty()
@IsNotEmpty()
@IsNumber()
age: number;
+ @ApiPropertyOptional() // @ApiProperty({ required: false }) でもOK
@IsOptional()
@IsDate()
birthday?: Date;
}
description, exampleも必要に応じて追加できます。
export class CreateSampleDto {
@ApiProperty({
+ description: 'サンプルデータの名前(これがswaggerのコメントになる)',
+ example: 'miramira',
})
@IsNotEmpty()
@IsString()
name: string;
@ApiProperty({
+ description: 'サンプルデータの年齢(これがswaggerのコメントになる)',
+ example: 22,
})
@IsNotEmpty()
@IsNumber()
age: number;
@ApiPropertyOptional({
+ description: 'サンプルデータの誕生日(これがswaggerのコメントになる)',
+ example: '2000-01-01',
})
@IsOptional()
@IsDate()
birthday?: Date;
descriptionとexampleが追加されていますね!あっぱれ😀
@ApiProperty
さえ書きたくない
そこはNest.js先生!
お安い御用のようです。先に結果を載せます。
export class CreateSampleDto {
- @ApiProperty({
- description: 'サンプルデータの名前(これがswaggerのコメントになる)',
- example: 'miramira',
- })
+ /**
+ * サンプルデータの名前(これがswaggerのコメントになる)
+ * @example miramira(これがswaggerのサンプル値になる)
+ */
@IsNotEmpty()
@IsString()
name: string;
- @ApiProperty({
- description: 'サンプルデータの年齢(これがswaggerのコメントになる)',
- example: 22,
- })
+ /**
+ * サンプルデータの年齢(これがswaggerのコメントになる)
+ * @example 22(これがswaggerのサンプル値になる)
+ */
@IsNotEmpty()
@IsNumber()
age: number;
- @ApiPropertyOptional({
- description: 'サンプルデータの誕生日(これがswaggerのコメントになる)',
- example: '2000-01-01',
- })
+ /**
+ * サンプルデータの誕生日(これがswaggerのコメントになる)
+ * @example '2000-01-01'(これがswaggerのサンプル値になる)
+ */
@IsOptional()
@IsDate()
birthday?: Date;
}
コメントが description, exampleとして反映され、class-validator
のバリデーションルールを再利用できました!
設定方法
NestCLIにコンパイラオプションを追加するだけです。
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
+ "compilerOptions": {
+ "plugins": [
+ {
+ "name": "@nestjs/swagger",
+ "options": {
+ "classValidatorShim": true,
+ "introspectComments": true
+ }
+ }
+ ]
+ }
}
compilerOptions.plulgins.options
は PluginOptions
インターフェイスを満たしていればOKです。
interface PluginOptions {
// DTOファイルのサフィックスを追加・削除できる
// default) ['.dto.ts', '.entity.ts']
dtoFileNameSuffix?: string[];
// コントローラーファイルのサフィックスを追加・削除できる
// default) ['.controller.ts']
controllerFileNameSuffix?: string[];
// class-validatorのデコレーターをswaggerの記述に再利用する
// default) true
classValidatorShim?: boolean;
// @ApiProperty()のどのキーにコメントを設定するか指定する
// default) 'description'
dtoKeyOfComment?: string;
// @ApiOperation()のどのキーにコメントを設定するか指定する
// default) 'description'
controllerKeyOfComment?: string;
// コメントでプロパティの説明や、サンプル値を記述できる
// default) false
introspectComments?: boolean;
}
今回は classValidatorShim
と introspectComments
を明示的に true にすることで、DTOで定義したバリデーションルールをSwaggerに反映し、コメントでプロパティの説明や初期値を設定できるようにしました!
おわりに
中級エンジニアを育成するプラハチャレンジ、ついに最終章へ突入しました!
最後の目玉となる「チーム開発」では、これまで学んだことを総動員して、技術選定、疑似POへのヒアリング、設計からテストまでを1スプリント2週間 × 4スプリントで行っていきます。
現在募集が止まっていますが、6期もしばらくしたら開催されると思うので、実務2年くらいまでのエンジニャーさんたちはぜひ、waiting listに入っておきましょう!めっちゃたのしいよ😎
Discussion