エンジニアを目指す初学者に向けて、わかりやすく解説したブログです。

【NestJS】環境変数の型定義とバリデーションを行う

やりたいこと

  • 環境変数が未設定のときにエラーを出したい
  • コード内で環境変数を扱うときに型推論が活かされるようにしたい

バリデーションの方法

Icon in a page linkDocumentation | NestJS - A progressive Node.js framework

バリデーションの実装方針は大体3通りほど存在する。

  1. joiを使う(公式ドキュメントに記載あり)
  2. class-validatorを使う(公式ドキュメントに記載あり)
  3. zodを使う(公式ドキュメントには記載なしだが、一般的なスキーマ定義方法としてよく知られている)

今回は、型定義とバリデーションが一元管理でき、設定も複雑にならないclass-validatorを使った方法を紹介する。

手順

1. 必要なライブラリをインストール

pnpm add @nestjs/config class-validator class-transformer

2. バリデーション定義ファイルを作成する

ほぼ公式ドキュメント通りに書く。

今回は3種類の環境変数を定義。

  • NODE_ENVdevelopment or productionを取りうる
  • TZ:日本時間固定
  • DATABASE_URL:PostgreSQLに接続するためのURL
// env.validation.ts
import { plainToInstance } from 'class-transformer';
import { IsEnum, IsString, validateSync } from 'class-validator';

enum Environment {
  Development = 'development',
  Production = 'production',
}

export class EnvironmentVariables {
  @IsEnum(Environment)
  NODE_ENV: Environment;

  @IsString()
  TZ = 'Asia/Tokyo';

  @IsString()
  DATABASE_URL: string;
}

export function validate(config: Record<string, unknown>) {
  const validatedConfig = plainToInstance(EnvironmentVariables, config, {
    enableImplicitConversion: true,
  });
  const errors = validateSync(validatedConfig, {
    skipMissingProperties: false,
  });

  if (errors.length > 0) {
    throw new Error(errors.toString());
  }
  return validatedConfig;
}

3. app.module.tsにバリデーション関数を追加する

ConfigModule.forRoot()の関数の中に、先程作成した関数を設定する。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { validate } from './env.validaton';

@Module({
  imports: [
    ConfigModule.forRoot({
      validate: validate,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

4. 使い方

コード内で環境変数を呼び出すには、以下のように実装する。

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { EnvironmentVariables } from './env.validaton';

@Injectable()
export class AppService implements OnApplicationShutdown {
  constructor(
    private readonly configService: ConfigService<EnvironmentVariables>,  // ここで型定義したものを入れる
  ) {}

  getHello(): string {
    const envName = this.configService.get('NODE_ENV', { infer: true });  // infer: trueで推論を有効化する
    return `Hello World! env=${envName}`;
  }
}