Konfiguratsiya
Ilovalar ko'pincha turli environmentlarda ishlaydi. Environmentga qarab turli konfiguratsiya sozlamalari ishlatilishi kerak. Masalan, odatda local environment faqat local DB instan
Ilovalar ko'pincha turli environmentlarda ishlaydi. Environmentga qarab turli konfiguratsiya sozlamalari ishlatilishi kerak. Masalan, odatda local environment faqat local DB instansiyasi uchun yaroqli bo'lgan maxsus ma'lumotlar bazasi kredensiallariga tayanadi. Production environment esa alohida DB kredensiallar to'plamidan foydalanadi. Konfiguratsiya o'zgaruvchilari o'zgarib turishi sababli, eng yaxshi amaliyot - konfiguratsiya o'zgaruvchilarini environmentda saqlash.
Tashqi aniqlangan environment o'zgaruvchilari Node.js ichida process.env globali orqali ko'rinadi. Bir nechta environment muammosini har bir environmentda environment o'zgaruvchilarini alohida o'rnatish orqali hal qilishga urinib ko'rishimiz mumkin. Bu tezda boshqarib bo'lmas holga keladi, ayniqsa development va testing environmentlarida bu qiymatlarni oson mock qilish va/yoki o'zgartirish kerak bo'lganda.
Node.js ilovalarida .env fayllaridan foydalanish odatiy bo'lib, bunda har bir key muayyan qiymatni ifodalovchi key-value juftliklari saqlanadi va har bir environmentni ifodalaydi. Turli environmentlarda ilovani ishga tushirish shunchaki to'g'ri .env faylini almashtirishdan iborat bo'ladi.
Nestda bu texnikadan foydalanish uchun yaxshi yondashuv - mos .env faylini yuklaydigan ConfigService ni taqdim etuvchi ConfigModule yaratish. Bunday modulni o'zingiz yozishni tanlashingiz mumkin, ammo qulaylik uchun Nest tayyor holda @nestjs/config paketini taqdim etadi. Ushbu bobda aynan shu paketni ko'rib chiqamiz.
O'rnatish
Ishlatishni boshlash uchun avval kerakli bog'liqlikni o'rnating.
1$ npm i --save @nestjs/config@nestjs/config paketi ichkarida dotenv dan foydalanadi.
@nestjs/config TypeScript 4.1 yoki undan yuqorini talab qiladi.
Boshlash
O'rnatish jarayoni tugagach, ConfigModule ni import qilamiz. Odatda uni root AppModule ga import qilib, .forRoot() statik metodi bilan xatti-harakatini boshqaramiz. Ushbu bosqichda environment o'zgaruvchilarining key/value juftliklari parse qilinadi va yechiladi. Keyinroq ConfigModule ning ConfigService sinfiga boshqa feature modullardan qanday kirishni bir nechta usulda ko'ramiz.
1import { Module } from '@nestjs/common';
2import { ConfigModule } from '@nestjs/config';
3
4@Module({
5 imports: [ConfigModule.forRoot()],
6})
7export class AppModule {}Yuqoridagi kod default joylashuvdan (project root katalogi) .env faylini yuklaydi va parse qiladi, .env faylidagi key/value juftliklarini process.env ga berilgan environment o'zgaruvchilari bilan birlashtiradi va natijani ConfigService orqali kirish mumkin bo'lgan xususiy tuzilmada saqlaydi. forRoot() metodi ConfigService provayderini ro'yxatdan o'tkazadi; u ushbu parse qilingan/birlashtirilgan konfiguratsiya o'zgaruvchilarini o'qish uchun get() metodini taqdim etadi. @nestjs/config dotenv ga tayanadiganligi sababli, environment o'zgaruvchi nomlaridagi ziddiyatlarni hal qilishda o'sha paket qoidalaridan foydalanadi. Agar key runtime environmentda environment o'zgaruvchisi sifatida (masalan, OS shell exportlari orqali export DATABASE_USER=test) ham, .env faylida ham mavjud bo'lsa, runtime environmentdagi o'zgaruvchi ustunlik qiladi.
Namunaviy .env fayli quyidagicha ko'rinadi:
1DATABASE_USER=test
2DATABASE_PASSWORD=testAgar ayrim env o'zgaruvchilar ConfigModule yuklanishidan va Nest ilovasi bootstrapping qilinishidan oldin ham mavjud bo'lishi kerak bo'lsa (masalan, NestFactory#createMicroservice metodiga mikroservis konfiguratsiyasini uzatish uchun), Nest CLI ning --env-file opsiyasidan foydalanishingiz mumkin. Bu opsiya ilova ishga tushishidan oldin yuklanishi kerak bo'lgan .env fayl pathini ko'rsatish imkonini beradi. --env-file flag qo'llab-quvvatlashi Node v20 da joriy etilgan, batafsil ma'lumot uchun hujjatlarga qarang.
1$ nest start --env-file .envMaxsus env fayl pathi
Standart holatda paket ilovaning root katalogida .env faylini qidiradi. .env fayli uchun boshqa path ko'rsatish uchun forRoot() ga uzatiladigan (ixtiyoriy) opsiyalar obyektidagi envFilePath xossasini sozlang, quyidagicha:
1ConfigModule.forRoot({
2 envFilePath: '.development.env',
3});.env fayllari uchun bir nechta pathni quyidagicha ko'rsatishingiz mumkin:
1ConfigModule.forRoot({
2 envFilePath: ['.env.development.local', '.env.development'],
3});Agar o'zgaruvchi bir nechta faylda topilsa, birinchisi ustunlik qiladi.
Env o'zgaruvchilarini yuklashni o'chirish
Agar .env faylini yuklamoqchi bo'lmasangiz, balki runtime environmentdan (masalan, OS shell exportlari export DATABASE_USER=test) environment o'zgaruvchilariga kirishni xohlasangiz, opsiyalar obyektidagi ignoreEnvFile xossasini true qilib qo'ying, quyidagicha:
1ConfigModule.forRoot({
2 ignoreEnvFile: true,
3});Modulni global ishlatish
ConfigModule ni boshqa modullarda ishlatmoqchi bo'lsangiz, uni import qilishingiz kerak (istalgan Nest modulida bo'lgani kabi). Muqobil ravishda, opsiyalar obyektidagi isGlobal xossasini true qilib, uni global modul sifatida e'lon qilishingiz mumkin. Bunda ConfigModule root modulda (masalan, AppModule) yuklangach, boshqa modullarda uni import qilishingiz shart bo'lmaydi.
1ConfigModule.forRoot({
2 isGlobal: true,
3});Maxsus konfiguratsiya fayllari
Murakkabroq loyihalar uchun nested konfiguratsiya obyektlarini qaytaradigan maxsus konfiguratsiya fayllaridan foydalanishingiz mumkin. Bu bog'liq konfiguratsiya sozlamalarini funksiyaga ko'ra guruhlash imkonini beradi (masalan, DBga oid sozlamalar), hamda bog'liq sozlamalarni alohida fayllarda saqlab, ularni mustaqil boshqarishni osonlashtiradi.
Maxsus konfiguratsiya fayli konfiguratsiya obyektini qaytaradigan factory funksiyani eksport qiladi. Konfiguratsiya obyekti istalgan darajada nested bo'lgan oddiy JavaScript obyekt bo'lishi mumkin. process.env obyekti to'liq yechilgan environment variable key/value juftliklarini o'z ichiga oladi (.env fayli va tashqi aniqlangan o'zgaruvchilar yuqorida ta'riflanganidek yechilib va birlashtiriladi). Qaytariladigan konfiguratsiya obyektini siz nazorat qilganingiz sababli, qiymatlarni mos tipga cast qilish, default qiymatlar berish va hokazo kabi kerakli mantiqni qo'shishingiz mumkin. Masalan:
1export default () => ({
2 port: parseInt(process.env.PORT, 10) || 3000,
3 database: {
4 host: process.env.DATABASE_HOST,
5 port: parseInt(process.env.DATABASE_PORT, 10) || 5432
6 }
7});Bu faylni ConfigModule.forRoot() metodiga uzatadigan opsiyalar obyektidagi load xossasi orqali yuklaymiz:
1import configuration from './config/configuration';
2
3@Module({
4 imports: [
5 ConfigModule.forRoot({
6 load: [configuration],
7 }),
8 ],
9})
10export class AppModule {}load xossasiga berilgan qiymat massivdir, bu bir nechta konfiguratsiya faylini yuklash imkonini beradi (masalan, load: [databaseConfig, authConfig])
Maxsus konfiguratsiya fayllari bilan YAML fayllarini ham boshqarishingiz mumkin. Quyida YAML formatidagi konfiguratsiya misoli:
1http:
2 host: 'localhost'
3 port: 8080
4
5db:
6 postgres:
7 url: 'localhost'
8 port: 5432
9 database: 'yaml-db'
10
11 sqlite:
12 database: 'sqlite.db'YAML fayllarini o'qish va parse qilish uchun js-yaml paketidan foydalanamiz.
1$ npm i js-yaml
2$ npm i -D @types/js-yamlPaket o'rnatilgach, yuqorida yaratgan YAML faylini yuklash uchun yaml#load funksiyasidan foydalanamiz.
1import { readFileSync } from 'node:fs';
2import { join } from 'node:path';
3import * as yaml from 'js-yaml';
4
5const YAML_CONFIG_FILENAME = 'config.yaml';
6
7export default () => {
8 return yaml.load(
9 readFileSync(join(__dirname, YAML_CONFIG_FILENAME), 'utf8'),
10 ) as Record<string, any>;
11};Nest CLI build jarayonida "assets" (TS bo'lmagan fayllar)ni avtomatik ravishda dist papkasiga ko'chirmaydi. YAML fayllaringiz ko'chirilishini ta'minlash uchun nest-cli.json faylida compilerOptions#assets obyektida buni ko'rsatishingiz kerak. Masalan, agar config papkasi src papkasi bilan bir xil darajada bo'lsa, compilerOptions#assets ga "assets": [{{ '{' }}"include": "../config/*.yaml", "outDir": "./dist/config"{{ '}' }}] qiymatini qo'shing. Batafsil bu yerda.
Qisqa eslatma: konfiguratsiya fayllari avtomatik validatsiya qilinmaydi, hatto NestJS ConfigModuleida validationSchema opsiyasidan foydalansangiz ham. Agar validatsiya kerak bo'lsa yoki transformatsiyalarni qo'llamoqchi bo'lsangiz, buni konfiguratsiya obyektini to'liq nazorat qiladigan factory funksiya ichida bajarishingiz kerak. Bu kerakli custom validatsiya mantiqini amalga oshirishga imkon beradi.
Masalan, port ma'lum bir diapazonda ekanini ta'minlash uchun factory funksiyasiga validatsiya qadamini qo'shishingiz mumkin:
1export default () => {
2 const config = yaml.load(
3 readFileSync(join(__dirname, YAML_CONFIG_FILENAME), 'utf8'),
4 ) as Record<string, any>;
5
6 if (config.http.port < 1024 || config.http.port > 49151) {
7 throw new Error('HTTP port must be between 1024 and 49151');
8 }
9
10 return config;
11};Endi port ko'rsatilgan diapazondan tashqarida bo'lsa, ilova ishga tushishda xato tashlaydi.
ConfigServicedan foydalanish
ConfigService dan konfiguratsiya qiymatlarini olish uchun avvalo ConfigService ni in'eksiya qilishimiz kerak. Istalgan provayder kabi, uni ishlatadigan modulga o'zini o'z ichiga olgan ConfigModule ni import qilishimiz kerak (agar ConfigModule.forRoot() ga uzatiladigan opsiyalar obyektida isGlobal xossasini true qilmagan bo'lsangiz). Uni feature modulga quyidagicha import qiling.
1@Module({
2 imports: [ConfigModule],
3 // ...
4})So'ng uni odatiy konstruktor in'eksiyasi orqali kiriting:
1constructor(private configService: ConfigService) {}ConfigService@nestjs/config paketidan import qilinadi.
Va sinfda undan foydalaning:
1// get an environment variable
2const dbUser = this.configService.get<string>('DATABASE_USER');
3
4// get a custom configuration value
5const dbHost = this.configService.get<string>('database.host');Yuqorida ko'rsatilganidek, oddiy environment o'zgaruvchisini olish uchun configService.get() metodidan foydalanib o'zgaruvchi nomini uzating. Yuqorida ko'rsatilgandek, TypeScript type hinting uchun tipni uzatishingiz mumkin (masalan, get<string>(...)). get() metodi nested custom konfiguratsiya obyektini ham ko'ra oladi (Custom configuration file orqali yaratilgan), bu yuqoridagi ikkinchi misolda ko'rsatilgan.
Siz butun nested custom konfiguratsiya obyektini interfeysni type hint sifatida berib ham olishingiz mumkin:
1interface DatabaseConfig {
2 host: string;
3 port: number;
4}
5
6const dbConfig = this.configService.get<DatabaseConfig>('database');
7
8// you can now use `dbConfig.port` and `dbConfig.host`
9const port = dbConfig.port;get() metodi ixtiyoriy ikkinchi argumentni ham qabul qiladi, u default qiymatni belgilaydi va key mavjud bo'lmasa qaytariladi, quyidagicha:
1// use "localhost" when "database.host" is not defined
2const dbHost = this.configService.get<string>('database.host', 'localhost');ConfigService ikkita ixtiyoriy generic (tip argumenti)ga ega. Birinchisi mavjud bo'lmagan config xossasiga kirishni oldini olishga yordam beradi. Uni quyidagicha ishlating:
1interface EnvironmentVariables {
2 PORT: number;
3 TIMEOUT: string;
4}
5
6// somewhere in the code
7constructor(private configService: ConfigService<EnvironmentVariables>) {
8 const port = this.configService.get('PORT', { infer: true });
9
10 // TypeScript Error: this is invalid as the URL property is not defined in EnvironmentVariables
11 const url = this.configService.get('URL', { infer: true });
12}infer xossasi true bo'lsa, ConfigService#get metodi interfeys asosida xossa tipini avtomatik aniqlaydi, masalan PORT EnvironmentVariables interfeysida number tipi bo'lgani uchun typeof port === "number" (agar TypeScriptning strictNullChecks flagidan foydalanmayotgan bo'lsangiz).
Shuningdek, infer imkoniyati bilan, dot notation ishlatilganda ham nested custom konfiguratsiya obyektining xossasi tipini aniqlashingiz mumkin, quyidagicha:
1constructor(private configService: ConfigService<{ database: { host: string } }>) {
2 const dbHost = this.configService.get('database.host', { infer: true })!;
3 // typeof dbHost === "string" |
4 // +--> non-null assertion operator
5}Ikkinchi generic birinchisiga tayanadi va strictNullChecks yoqilganda ConfigService metodlari qaytarishi mumkin bo'lgan barcha undefined tiplarni olib tashlash uchun type assertion vazifasini bajaradi. Masalan:
1// ...
2constructor(private configService: ConfigService<{ PORT: number }, true>) {
3 // ^^^^
4 const port = this.configService.get('PORT', { infer: true });
5 // ^^^ The type of port will be 'number' thus you don't need TS type assertions anymore
6}ConfigService#get metodi qiymatlarni faqat custom konfiguratsiya fayllaridan olishini va process.env o'zgaruvchilarini e'tiborsiz qoldirishini istasangiz, ConfigModule ning forRoot() metodiga uzatiladigan opsiyalar obyektida skipProcessEnv opsiyasini true qilib qo'ying.
Konfiguratsiya namespace'lari
ConfigModule yuqorida Custom configuration files bo'limida ko'rsatilganidek, bir nechta maxsus konfiguratsiya fayllarini aniqlash va yuklash imkonini beradi. O'sha bo'limda ko'rsatilgandek nested konfiguratsiya obyektlari bilan murakkab konfiguratsiya ierarxiyalarini boshqarishingiz mumkin. Muqobil ravishda, registerAs() funksiyasi bilan "namespaced" konfiguratsiya obyektini qaytarishingiz mumkin, quyidagicha:
1export default registerAs('database', () => ({
2 host: process.env.DATABASE_HOST,
3 port: process.env.DATABASE_PORT || 5432
4}));Custom konfiguratsiya fayllarida bo'lgani kabi, registerAs() factory funksiyasi ichida process.env obyekti to'liq yechilgan environment variable key/value juftliklarini o'z ichiga oladi (.env fayli va tashqi aniqlangan o'zgaruvchilar yuqorida ta'riflanganidek yechilib va birlashtiriladi).
registerAs funksiyasi @nestjs/config paketidan eksport qilinadi.
Namespaced konfiguratsiyani forRoot() metodining opsiyalar obyektidagi load xossasi orqali, custom konfiguratsiya faylini yuklagandek, yuklang:
1import databaseConfig from './config/database.config';
2
3@Module({
4 imports: [
5 ConfigModule.forRoot({
6 load: [databaseConfig],
7 }),
8 ],
9})
10export class AppModule {}Endi database namespace'dan host qiymatini olish uchun dot notationdan foydalaning. registerAs() funksiyasiga birinchi argument sifatida berilgan namespace nomiga mos ravishda, xossa nomidan oldin 'database' prefiksini ishlating:
1const dbHost = this.configService.get<string>('database.host');Yana bir maqbul variant - database namespace'ni bevosita in'eksiya qilish. Bu strong typingdan foydalanish imkonini beradi:
1constructor(
2 @Inject(databaseConfig.KEY)
3 private dbConfig: ConfigType<typeof databaseConfig>,
4) {}ConfigType@nestjs/config paketidan eksport qilinadi.
Modullarda namespaced konfiguratsiyalar
Namespaced konfiguratsiyani ilovangizdagi boshqa modul uchun konfiguratsiya obyektiga aylantirish uchun konfiguratsiya obyektining .asProvider() metodidan foydalanishingiz mumkin. Bu metod namespaced konfiguratsiyani provayderga aylantiradi va uni ishlatmoqchi bo'lgan modulning forRootAsync() (yoki boshqa ekvivalent metodiga) uzatish mumkin.
Misol:
1import databaseConfig from './config/database.config';
2
3@Module({
4 imports: [
5 TypeOrmModule.forRootAsync(databaseConfig.asProvider()),
6 ],
7}).asProvider() metodi qanday ishlashini tushunish uchun uning qaytadigan qiymatini ko'rib chiqamiz:
1// Return value of the .asProvider() method
2{
3 imports: [ConfigModule.forFeature(databaseConfig)],
4 useFactory: (configuration: ConfigType<typeof databaseConfig>) => configuration,
5 inject: [databaseConfig.KEY]
6}Ushbu tuzilma namespaced konfiguratsiyalarni modullarga muammosiz integratsiya qilishga imkon beradi, ilovangizni tartibli va modulli holatda ushlab, boilerplate va takroriy kod yozmasdan.
Environment o'zgaruvchilarini keshlash
process.env ga kirish sekin bo'lishi mumkinligi sababli, ConfigService#get metodi process.env dagi o'zgaruvchilar uchun ishlaganda performance oshishi uchun ConfigModule.forRoot() ga uzatiladigan opsiyalar obyektida cache xossasini true qilib qo'yishingiz mumkin.
1ConfigModule.forRoot({
2 cache: true,
3});Qisman ro'yxatdan o'tkazish
Hozirgacha konfiguratsiya fayllarini root modulimizda (masalan, AppModule) forRoot() metodi bilan qayta ishladik. Balki sizda murakkabroq loyiha tuzilmasi bor, feature'ga xos konfiguratsiya fayllari bir nechta kataloglarda joylashgan. Bu fayllarning barchasini root modulda yuklash o'rniga, @nestjs/config paketi partial registration deb ataladigan imkoniyatni taqdim etadi; u har bir feature modulga tegishli konfiguratsiya fayllarinigina referenslaydi. Qisman ro'yxatdan o'tkazishni feature modulda forFeature() statik metodi bilan bajaring, quyidagicha:
1import databaseConfig from './config/database.config';
2
3@Module({
4 imports: [ConfigModule.forFeature(databaseConfig)],
5})
6export class DatabaseModule {}Ba'zi holatlarda, qisman ro'yxatdan o'tkazilgan xossalarga konstruktor ichida emas, onModuleInit() hook'i orqali kirish talab qilinishi mumkin. Buning sababi forFeature() metodi modul inicializatsiyasi vaqtida ishlaydi va modullar inicializatsiyasi tartibi noaniq bo'lishi mumkin. Agar boshqa modul yuklagan qiymatlarga konstruktor ichida kirilsa, konfiguratsiya bog'liq bo'lgan modul hali inicializatsiya bo'lmagan bo'lishi mumkin. onModuleInit() metodi faqat bog'liq bo'lgan barcha modullar inicializatsiya bo'lgandan keyin ishlaydi, shuning uchun bu usul xavfsiz.
Schema validatsiyasi
Kerakli environment o'zgaruvchilari berilmagan yoki ular muayyan validatsiya qoidalariga mos kelmagan bo'lsa, ilova ishga tushishda istisno tashlash standard amaliyot hisoblanadi. @nestjs/config paketi buni ikki xil yo'l bilan qilishga imkon beradi:
- Joi o'rnatilgan validator. Joi bilan siz obyekt sxemasini aniqlab, JavaScript obyektlarini unga nisbatan validatsiya qilasiz.
- Environment o'zgaruvchilarini input sifatida oladigan maxsus
validate()funksiyasi.
Joi'dan foydalanish uchun Joi paketini o'rnatishimiz kerak:
1$ npm install --save joiEndi Joi validatsiya sxemasini aniqlab, uni forRoot() metodining opsiyalar obyektidagi validationSchema xossasi orqali uzatamiz, quyida ko'rsatilganidek:
1import * as Joi from 'joi';
2
3@Module({
4 imports: [
5 ConfigModule.forRoot({
6 validationSchema: Joi.object({
7 NODE_ENV: Joi.string()
8 .valid('development', 'production', 'test', 'provision')
9 .default('development'),
10 PORT: Joi.number().port().default(3000),
11 }),
12 }),
13 ],
14})
15export class AppModule {}Standart holatda sxema kalitlarining barchasi ixtiyoriy deb hisoblanadi. Bu yerda biz NODE_ENV va PORT uchun default qiymatlarni berdik; agar bu o'zgaruvchilarni environmentda taqdim etmasak (.env fayli yoki process environment), shu qiymatlar ishlatiladi. Muqobil ravishda, required() validatsiya metodidan foydalanib qiymat environmentda majburiy bo'lishini talab qilishingiz mumkin (.env fayli yoki process environment). Bu holatda validatsiya bosqichi o'zgaruvchi berilmagan bo'lsa istisno tashlaydi. Validatsiya sxemalarini qanday qurish bo'yicha batafsil Joi validation methodsga qarang.
Standart holatda noma'lum environment o'zgaruvchilari (kalitlari sxemada mavjud bo'lmaganlari) ruxsat etiladi va validatsiya istisnosini keltirib chiqarmaydi. Standart holatda barcha validatsiya xatolari qayd etiladi. Bu xatti-harakatlarni forRoot() opsiyalar obyektidagi validationOptions kaliti orqali opsiyalar obyektini uzatib o'zgartirishingiz mumkin. Bu opsiyalar obyektida Joi validation options taqdim etadigan standard validatsiya opsiyalari bo'lishi mumkin. Masalan, yuqoridagi ikki sozlamani teskari qilish uchun quyidagicha opsiyalar uzating:
1import * as Joi from 'joi';
2
3@Module({
4 imports: [
5 ConfigModule.forRoot({
6 validationSchema: Joi.object({
7 NODE_ENV: Joi.string()
8 .valid('development', 'production', 'test', 'provision')
9 .default('development'),
10 PORT: Joi.number().port().default(3000),
11 }),
12 validationOptions: {
13 allowUnknown: false,
14 abortEarly: true,
15 },
16 }),
17 ],
18})
19export class AppModule {}@nestjs/config paketining default sozlamalari:
allowUnknown: environment o'zgaruvchilarida noma'lum kalitlarga ruxsat berish-bermasligini boshqaradi. DefaulttrueabortEarly:truebo'lsa birinchi xatoda validatsiyani to'xtatadi;falsebo'lsa barcha xatolarni qaytaradi. Defaultfalse.
E'tibor bering, validationOptions obyektini uzatishga qaror qilsangiz, aniq berilmagan har qanday sozlama Joining standard default qiymatlariga o'rnatiladi (@nestjs/config defaultlari emas). Masalan, custom validationOptions obyektida allowUnknown ko'rsatilmasa, u Joi default qiymati false bo'ladi. Shu sababli custom obyekt ichida bu ikki sozlamaning ikkalasini ham ko'rsatish xavfsizroq bo'ladi.
Oldindan belgilangan environment o'zgaruvchilarini validatsiya qilishni o'chirish uchun forRoot() metodining opsiyalar obyektida validatePredefined atributini false ga o'rnating. Oldindan belgilangan environment o'zgaruvchilari - modul import qilinishidan oldin o'rnatilgan process o'zgaruvchilari (process.env o'zgaruvchilari). Masalan, ilovani PORT=3000 node main.js bilan ishga tushirsangiz, PORT oldindan belgilangan environment o'zgaruvchisidir.
Maxsus validate funksiyasi
Muqobil ravishda, env fayli va processdan olingan environment o'zgaruvchilarini o'z ichiga olgan obyektni qabul qiladigan va zarur bo'lsa ularni konvertatsiya/mutatsiya qiladigan, validatsiyalangan environment o'zgaruvchilarini qaytaradigan sinxron validate funksiyasini ko'rsatishingiz mumkin. Funksiya xato tashlasa, ilova bootstrapping qilinmaydi.
Bu misolda class-transformer va class-validator paketlaridan foydalanamiz. Avval quyidagilarni aniqlaymiz:
- validatsiya cheklovlariga ega sinf,
plainToInstancevavalidateSyncfunksiyalaridan foydalanadigan validate funksiyasi.
1import { plainToInstance } from 'class-transformer';
2import { IsEnum, IsNumber, Max, Min, validateSync } from 'class-validator';
3
4enum Environment {
5 Development = "development",
6 Production = "production",
7 Test = "test",
8 Provision = "provision",
9}
10
11class EnvironmentVariables {
12 @IsEnum(Environment)
13 NODE_ENV: Environment;
14
15 @IsNumber()
16 @Min(0)
17 @Max(65535)
18 PORT: number;
19}
20
21export function validate(config: Record<string, unknown>) {
22 const validatedConfig = plainToInstance(
23 EnvironmentVariables,
24 config,
25 { enableImplicitConversion: true },
26 );
27 const errors = validateSync(validatedConfig, { skipMissingProperties: false });
28
29 if (errors.length > 0) {
30 throw new Error(errors.toString());
31 }
32 return validatedConfig;
33}Shu bilan, validate funksiyasini ConfigModule konfiguratsiya opsiyasi sifatida ishlating, quyidagicha:
1import { validate } from './env.validation';
2
3@Module({
4 imports: [
5 ConfigModule.forRoot({
6 validate,
7 }),
8 ],
9})
10export class AppModule {}Maxsus getter funksiyalari
ConfigService kalit bo'yicha konfiguratsiya qiymatini olish uchun generik get() metodini taqdim etadi. Shuningdek, yanada tabiiy kodlash uslubi uchun getter funksiyalarini ham qo'shishimiz mumkin:
1@Injectable()
2export class ApiConfigService {
3 constructor(private configService: ConfigService) {}
4
5 get isAuthEnabled(): boolean {
6 return this.configService.get('AUTH_ENABLED') === 'true';
7 }
8}Endi getter funksiyasidan quyidagicha foydalanishimiz mumkin:
1@Injectable()
2export class AppService {
3 constructor(apiConfigService: ApiConfigService) {
4 if (apiConfigService.isAuthEnabled) {
5 // Authentication is enabled
6 }
7 }
8}Environment o'zgaruvchilari yuklangan hook
Agar modul konfiguratsiyasi environment o'zgaruvchilariga bog'liq bo'lsa va bu o'zgaruvchilar .env faylidan yuklansa, process.env obyektiga murojaat qilishdan oldin fayl yuklanganini ta'minlash uchun ConfigModule.envVariablesLoaded hook'idan foydalanishingiz mumkin, quyidagi misolga qarang:
1export async function getStorageModule() {
2 await ConfigModule.envVariablesLoaded;
3 return process.env.STORAGE === 'S3' ? S3StorageModule : DefaultStorageModule;
4}Bu konstruktsiya ConfigModule.envVariablesLoaded Promise resolve bo'lgach, barcha konfiguratsiya o'zgaruvchilari yuklanganini kafolatlaydi.
Shartli modul konfiguratsiyasi
Ba'zan modulni shartli tarzda yuklash va shartni env o'zgaruvchisida ko'rsatish kerak bo'ladi. Yaxshiyamki, @nestjs/config buni qilish uchun ConditionalModule ni taqdim etadi.
1@Module({
2 imports: [
3 ConfigModule.forRoot(),
4 ConditionalModule.registerWhen(FooModule, 'USE_FOO'),
5 ],
6})
7export class AppModule {}Yuqoridagi modul .env faylida USE_FOO env o'zgaruvchisi uchun false qiymati bo'lmasa, FooModule ni yuklaydi. Siz o'zingizning shart funksiyangizni ham uzatishingiz mumkin; bu funksiya process.env havolasini qabul qiladi va ConditionalModule ishlatishi uchun boolean qaytarishi kerak:
1@Module({
2 imports: [
3 ConfigModule.forRoot(),
4 ConditionalModule.registerWhen(
5 FooBarModule,
6 (env: NodeJS.ProcessEnv) => !!env['foo'] && !!env['bar'],
7 ),
8 ],
9})
10export class AppModule {}ConditionalModule dan foydalanganda ConfigModule ham ilovada yuklanganiga ishonch hosil qilish muhim, shunda ConfigModule.envVariablesLoaded hook'i to'g'ri referenslanadi va ishlatiladi. Agar hook 5 soniya ichida true bo'lib o'zgarmasa yoki registerWhen metodining uchinchi opsiya parametrida foydalanuvchi tomonidan millisekundlarda belgilangan timeout tugasa, ConditionalModule xato tashlaydi va Nest ilovani ishga tushirishni bekor qiladi.
Kengaytiriladigan o'zgaruvchilar
@nestjs/config paketi environment o'zgaruvchilarini kengaytirishni qo'llab-quvvatlaydi. Bu texnika yordamida nested environment o'zgaruvchilarini yaratishingiz mumkin, bunda bitta o'zgaruvchi boshqasining ta'rifida ishlatiladi. Masalan:
1APP_URL=mywebsite.com
2SUPPORT_EMAIL=support@${APP_URL}Ushbu konstruktsiyada SUPPORT_EMAIL o'zgaruvchisi 'support@mywebsite.com' ga yechiladi. ${{ '{' }}...{{ '}' }} sintaksisidan foydalanib SUPPORT_EMAIL ta'rifida APP_URL qiymatini yechish yoqilganiga e'tibor bering.
Bu imkoniyat uchun @nestjs/config paketi ichkarida dotenv-expand dan foydalanadi.
Environment o'zgaruvchilarini kengaytirishni ConfigModule ning forRoot() metodiga uzatiladigan opsiyalar obyektida expandVariables xossasi orqali yoqing, quyida ko'rsatilgandek:
1@Module({
2 imports: [
3 ConfigModule.forRoot({
4 // ...
5 expandVariables: true,
6 }),
7 ],
8})
9export class AppModule {}main.ts ichida foydalanish
Konfiguratsiyamiz servis ichida saqlansa ham, uni main.ts faylida ishlatish mumkin. Shu tarzda ilova porti yoki CORS host kabi o'zgaruvchilarni saqlashda foydalanishingiz mumkin.
Unga kirish uchun app.get() metodidan, so'ng servis havolasidan foydalanishingiz kerak:
1const configService = app.get(ConfigService);So'ng get metodini konfiguratsiya kaliti bilan chaqirib, odatdagidek foydalanishingiz mumkin:
1const port = configService.get('PORT');