From ded673ec74877ccf8e8f11ff98d9fe2a9775cb26 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Thu, 28 Sep 2023 07:18:09 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20448:=20NestJS=E3=81=AE=E7=92=B0?= =?UTF-8?q?=E5=A2=83=E5=A4=89=E6=95=B0=E3=82=92=E3=83=90=E3=83=AA=E3=83=87?= =?UTF-8?q?=E3=83=BC=E3=82=BF=E3=81=A7=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [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) --- .../.devcontainer/docker-compose.yml | 1 - dictation_server/src/app.module.ts | 2 + .../src/common/validators/env.validator.ts | 198 ++++++++++++++++++ 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 dictation_server/src/common/validators/env.validator.ts diff --git a/dictation_server/.devcontainer/docker-compose.yml b/dictation_server/.devcontainer/docker-compose.yml index 47cf396..c3de580 100644 --- a/dictation_server/.devcontainer/docker-compose.yml +++ b/dictation_server/.devcontainer/docker-compose.yml @@ -2,7 +2,6 @@ version: '3' services: dictation_server: - env_file: ../.env build: . working_dir: /app/dictation_server ports: diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index 3deb54c..49b1d97 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -44,6 +44,7 @@ import { SortCriteriaRepositoryModule } from './repositories/sort_criteria/sort_ import { TemplateFilesRepositoryModule } from './repositories/template_files/template_files.repository.module'; import { WorktypesRepositoryModule } from './repositories/worktypes/worktypes.repository.module'; import { TemplatesService } from './features/templates/templates.service'; +import { validate } from './common/validators/env.validator'; @Module({ imports: [ @@ -60,6 +61,7 @@ import { TemplatesService } from './features/templates/templates.service'; ConfigModule.forRoot({ envFilePath: ['.env.local', '.env'], isGlobal: true, + validate, }), AuthModule, AdB2cModule, diff --git a/dictation_server/src/common/validators/env.validator.ts b/dictation_server/src/common/validators/env.validator.ts new file mode 100644 index 0000000..9ceea2a --- /dev/null +++ b/dictation_server/src/common/validators/env.validator.ts @@ -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) { + const validatedConfig = plainToClass(EnvValidator, config, { + enableImplicitConversion: true, + }); + + const errors = validateSync(validatedConfig, { + skipMissingProperties: false, + }); + + if (errors.length > 0) { + throw new Error(errors.toString()); + } + return validatedConfig; +}