ConfigModule — Environment Variables va Validation
Muammodan boshlaylik
Siz loyiha yozdingiz. Ma'lumotlar bazasiga ulanish uchun:
// ❌ Kod ichida to'g'ridan-to'g'ri yozilgan
const db = new DataSource({
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'mypassword123',
database: 'mydb',
});
Bu yondashuv bir nechta muammo keltirib chiqaradi:
- Xavfsizlik: Parol GitHub ga tushib qoladi
- Moslashuvchanlik: Lokal, test, production — har birida boshqa sozlamalar kerak, lekin kod o'zgartirilishi kerak
- Jamoa: Har bir dasturchi o'z parolini yozishi kerak
Yechim — environment variables (muhit o'zgaruvchilari). Sozlamalar kod ichida emas, alohida .env faylda saqlanadi.
# .env fayl — kod ichida emas
DB_HOST=localhost
DB_PORT=5432
DB_PASSWORD=mypassword123
NestJS da buni boshqarish uchun @nestjs/config moduli bor.
O'rnatish
npm install @nestjs/config
@nestjs/config ichida dotenv kutubxonasi bor — .env faylni o'qiydi va process.env ga yuklaydi.
Asosiy ishlatish
1. AppModule ga ulash
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // barcha modullarda ishlaydi, qayta import shart emas
}),
],
})
export class AppModule {}
isGlobal: true — nima uchun kerak? Har bir modulda ConfigModule ni import qilmaslik uchun. Bir marta ulasangiz — hamma joyda ishlaydi.
2. .env fayl yaratish
# .env
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=secret123
DB_NAME=myapp
JWT_SECRET=myjwtsecret
JWT_EXPIRES_IN=7d
PORT=3000
⚠️
.envfaylni hech qachon git ga qo'shmang..gitignorega qo'shing:.env .env.local .env.productionO'rniga
.env.examplefayl yarating — qiymatlar bo'sh, faqat kalitlar:DB_HOST= DB_PORT= DB_PASSWORD=
3. ConfigService orqali o'qish
// database/database.module.ts
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Module({
providers: [
{
provide: 'DATABASE',
useFactory: (config: ConfigService) => ({
host: config.get<string>('DB_HOST'),
port: config.get<number>('DB_PORT'),
password: config.get<string>('DB_PASSWORD'),
}),
inject: [ConfigService],
},
],
})
export class DatabaseModule {}
// auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(
private readonly config: ConfigService,
private readonly jwt: JwtService,
) {}
generateToken(userId: number) {
return this.jwt.sign(
{ sub: userId },
{
secret: this.config.get<string>('JWT_SECRET'),
expiresIn: this.config.get<string>('JWT_EXPIRES_IN'),
},
);
}
}
Turli muhitlar uchun alohida fayllar
Lokal, test va production uchun turli sozlamalar kerak bo'ladi:
.env ← standart (lokal)
.env.development ← development
.env.test ← test
.env.production ← production
ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.env.${process.env.NODE_ENV || 'development'}`,
})
# Ishga tushirish
NODE_ENV=production node dist/main.js
NODE_ENV=test jest
Konfiguratsiyani namespace larga bo'lish
Barcha o'zgaruvchilar bitta joyda bo'lsa — tartibsiz bo'ladi. registerAs bilan guruhlab bo'ladi:
// config/database.config.ts
import { registerAs } from '@nestjs/config';
export default registerAs('database', () => ({
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT, 10),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
name: process.env.DB_NAME,
}));
// config/jwt.config.ts
import { registerAs } from '@nestjs/config';
export default registerAs('jwt', () => ({
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '7d',
}));
// app.module.ts
import databaseConfig from './config/database.config';
import jwtConfig from './config/jwt.config';
ConfigModule.forRoot({
isGlobal: true,
load: [databaseConfig, jwtConfig],
})
// Ishlatish — namespace bilan
const dbHost = this.config.get<string>('database.host');
const jwtSecret = this.config.get<string>('jwt.secret');
Validatsiya — eng muhim qism
.env fayl yo'q bo'lsa yoki biror kalit yozilmagan bo'lsa — ilova ishga tushadi, lekin keyin noto'g'ri ishlaydi. Bu eng yomon holat: xato darhol emas, keyinroq chiqadi.
Yaxshisi: Ilova ishga tushayotganda barcha kerakli o'zgaruvchilar borligini tekshirish. Yo'q bo'lsa — darhol xato berish.
Buning uchun joi kutubxonasi ishlatiladi:
npm install joi
// app.module.ts
import * as Joi from 'joi';
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production', 'test')
.default('development'),
PORT: Joi.number().default(3000),
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().default(5432),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_NAME: Joi.string().required(),
JWT_SECRET: Joi.string().min(32).required(),
JWT_EXPIRES_IN: Joi.string().default('7d'),
}),
})
Endi DB_HOST bo'lmasa — ilova ishga tushmaydi va aniq xato beradi:
Error: Config validation error: "DB_HOST" is required
Tez-tez uchraydigan xatolar
1. config.get() undefined qaytaradi
const secret = this.config.get('JWT_SECRET'); // undefined
Sabab 1: .env faylda kalit yo'q yoki noto'g'ri yozilgan.
Sabab 2: ConfigModule.forRoot() AppModule da chaqirilmagan.
Sabab 3: isGlobal: true yo'q va modul import qilinmagan.
// Tekshirish uchun
console.log(this.config.get('JWT_SECRET')); // undefined bo'lsa — yuqoridagi sabablarni tekshiring
2. .env fayl o'qilmayapti
Sabab: Ilova ishga tushirilayotgan papka noto'g'ri. ConfigModule .env faylni joriy ishchi papkadan qidiradi.
# Xato — src/ papkasidan ishga tushirilsa
cd src && node main.js # .env topilmaydi
# To'g'ri — loyiha ildizidan
node dist/main.js # .env topiladi
3. Raqamli qiymat string sifatida keladi
const port = this.config.get('PORT'); // '3000' — string, number emas!
app.listen(port); // ishlaydi, lekin tip xato
Yechim: get<number>() yoki parseInt:
const port = this.config.get<number>('PORT');
// yoki
const port = parseInt(this.config.get('PORT'), 10);
Joi validatsiyasida Joi.number() qo'yilsa — avtomatik number ga aylantiriladi.
Xulosa
| Vazifa | Yechim |
|---|---|
.env o'qish |
ConfigModule.forRoot() |
| Qiymat olish | ConfigService.get<T>('KEY') |
| Barcha modullarda ishlash | isGlobal: true |
| Guruhlab saqlash | registerAs('namespace', () => {}) |
| Ishga tushishda tekshirish | validationSchema: Joi.object({}) |
Asosiy qoida: Hech qachon parol, token, API kalit kabi maxfiy ma'lumotlarni kod ichiga yozmang. Har doim .env dan o'qing va .gitignore ga qo'shing.
Keyingi dars
13-dars: Sequelize ORM + PostgreSQL — CRUD