Merged PR 448: NestJSの環境変数をバリデータでチェックする

## 概要
[Task2729: NestJSの環境変数をバリデータでチェックする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2729)

- 環境変数のバリデータを実装しました。
  - 起動時にバリデータのチェックに失敗したらエラーとなるようにしています。

## レビューポイント
- チェック対象の環境変数は適切か
  - チェック内容は適切か

## UIの変更
- なし

## 動作確認状況
- ローカルで確認

## 補足
- 参考:[環境変数をバリデーションしたい](https://zenn.dev/waddy/articles/nestjs-configuration-service#5.-%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%97%E3%81%9F%E3%81%84)
This commit is contained in:
makabe.t 2023-09-28 07:18:09 +00:00
parent deb08d81d2
commit ded673ec74
3 changed files with 200 additions and 1 deletions

View File

@ -2,7 +2,6 @@ version: '3'
services: services:
dictation_server: dictation_server:
env_file: ../.env
build: . build: .
working_dir: /app/dictation_server working_dir: /app/dictation_server
ports: ports:

View File

@ -44,6 +44,7 @@ import { SortCriteriaRepositoryModule } from './repositories/sort_criteria/sort_
import { TemplateFilesRepositoryModule } from './repositories/template_files/template_files.repository.module'; import { TemplateFilesRepositoryModule } from './repositories/template_files/template_files.repository.module';
import { WorktypesRepositoryModule } from './repositories/worktypes/worktypes.repository.module'; import { WorktypesRepositoryModule } from './repositories/worktypes/worktypes.repository.module';
import { TemplatesService } from './features/templates/templates.service'; import { TemplatesService } from './features/templates/templates.service';
import { validate } from './common/validators/env.validator';
@Module({ @Module({
imports: [ imports: [
@ -60,6 +61,7 @@ import { TemplatesService } from './features/templates/templates.service';
ConfigModule.forRoot({ ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'], envFilePath: ['.env.local', '.env'],
isGlobal: true, isGlobal: true,
validate,
}), }),
AuthModule, AuthModule,
AdB2cModule, AdB2cModule,

View File

@ -0,0 +1,198 @@
import { plainToClass } from 'class-transformer';
import {
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
validateSync,
} from 'class-validator';
/**
*
*/
export class EnvValidator {
// .env
@IsNotEmpty()
@IsString()
DB_HOST: string;
@IsNotEmpty()
@IsNumber()
DB_PORT: number;
@IsNotEmpty()
@IsNumber()
DB_EXTERNAL_PORT: number;
@IsNotEmpty()
@IsString()
DB_NAME: string;
@IsNotEmpty()
@IsString()
DB_ROOT_PASS: string;
@IsNotEmpty()
@IsString()
DB_USERNAME: string;
@IsNotEmpty()
@IsString()
DB_PASSWORD: string;
@IsOptional()
@IsString()
NO_COLOR: string;
@IsNotEmpty()
@IsNumber()
ACCESS_TOKEN_LIFETIME_WEB: number;
@IsNotEmpty()
@IsNumber()
REFRESH_TOKEN_LIFETIME_WEB: number;
@IsNotEmpty()
@IsNumber()
REFRESH_TOKEN_LIFETIME_DEFAULT: number;
@IsNotEmpty()
@IsString()
TENANT_NAME: string;
@IsNotEmpty()
@IsString()
SIGNIN_FLOW_NAME: string;
@IsNotEmpty()
@IsNumber()
EMAIL_CONFIRM_LIFETIME: number;
@IsNotEmpty()
@IsString()
APP_DOMAIN: string;
@IsNotEmpty()
@IsNumber()
STORAGE_TOKEN_EXPIRE_TIME: number;
// .env.local
@IsOptional()
@IsString()
STAGE: string;
@IsOptional()
@IsString()
CORS: string;
@IsNotEmpty()
@IsNumber()
PORT: number;
@IsNotEmpty()
@IsString()
AZURE_TENANT_ID: string;
@IsNotEmpty()
@IsString()
AZURE_CLIENT_ID: string;
@IsNotEmpty()
@IsString()
AZURE_CLIENT_SECRET: string;
@IsNotEmpty()
@IsString()
ADB2C_TENANT_ID: string;
@IsNotEmpty()
@IsString()
ADB2C_CLIENT_ID: string;
@IsNotEmpty()
@IsString()
ADB2C_CLIENT_SECRET: string;
@IsNotEmpty()
@IsString()
ADB2C_ORIGIN: string;
@IsNotEmpty()
@IsString()
KEY_VAULT_NAME: string;
@IsNotEmpty()
@IsString()
JWT_PRIVATE_KEY: string;
@IsNotEmpty()
@IsString()
JWT_PUBLIC_KEY: string;
@IsNotEmpty()
@IsString()
SENDGRID_API_KEY: string;
@IsNotEmpty()
@IsString()
MAIL_FROM: string;
@IsNotEmpty()
@IsString()
NOTIFICATION_HUB_NAME: string;
@IsNotEmpty()
@IsString()
NOTIFICATION_HUB_CONNECT_STRING: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_NAME_US: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_NAME_AU: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_NAME_EU: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_KEY_US: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_KEY_AU: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_KEY_EU: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_ENDPOINT_US: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_ENDPOINT_AU: string;
@IsNotEmpty()
@IsString()
STORAGE_ACCOUNT_ENDPOINT_EU: string;
}
export function validate(config: Record<string, unknown>) {
const validatedConfig = plainToClass(EnvValidator, config, {
enableImplicitConversion: true,
});
const errors = validateSync(validatedConfig, {
skipMissingProperties: false,
});
if (errors.length > 0) {
throw new Error(errors.toString());
}
return validatedConfig;
}