8.2-bob: Dependency Injection (chuqur)
8-QISM — NestJS (chuqur) · 2-mavzu
1. Kirish va motivatsiya
8.1-bobda NestJS arxitekturasini va dependency injection (DI) ni qisqacha ko'rdik. Endi uni — NestJS'ning eng muhim, eng kuchli, butun sehrining asosi bo'lgan mexanizmni — chuqur o'rganamiz. DI'ni tushunmasdan NestJS'ni "ishlataman" deyish mumkin, lekin uni bilaman deb bo'lmaydi. Bu bob — sizning NestJS bilimingizning poydevori (8.1'da boshladik; bu yerda to'liq, ichki ishlash bilan).
Dependency Injection — "bog'liqlikni kiritish" — class o'ziga kerakli bog'liqliklarni (boshqa service, DB, config) o'zi yaratmaydi, balki tashqaridan oladi (constructor orqali). NestJS'da bu — IoC konteyner (Inversion of Control — nazoratning teskari aylanishi) tomonidan avtomatik qilinadi. Siz constructor(private service: UserService) {} deysiz — NestJS UserServiceni (va uning barcha bog'liqliklarini) o'zi yaratib, ulab beradi. Bu — sehirdek ko'rinadi, lekin aniq, mantiqiy mexanizm (TS turlari + reflect-metadata — 7.6).
DI nega muhim? Uchta katta sabab: (1) Toza kod (class o'z ishiga e'tibor beradi, bog'liqlik yaratish bilan band emas); (2) Testlanadigan (test'da real DB o'rniga mock beramiz — DI buni oson qiladi — 8.11); (3) Moslashuvchan (implementatsiyani almashtirish oson — interface + DI — 9: SOLID DIP). Bu bob: DI nima va nega, IoC konteyner ichki ishlashi, provider turlari (useClass/useValue/useFactory/useExisting), injection token, custom provider, va scope — chuqur, promptdan ancha ko'p.
O'xshatish (DI): DI'siz — oshpaz o'zi dalaga borib, sabzavot ekib, yig'ib, keyin ovqat pishiradi (har bog'liqlikni o'zi yaratadi — band, chalkash). DI bilan — oshpazga tayyor masalliqlar yetkazib beriladi (constructor orqali), u faqat o'z ishini (ovqat pishirish) qiladi. Kim masalliq yetkazadi (IoC konteyner) — oshpazni qiziqtirmaydi. Test'da — soxta masalliq (mock) beramiz. Toza, moslashuvchan, sinaladigan.
Nega muhim?
- NestJS yuragi — butun framework DI ustiga qurilgan.
- Toza kod — class o'z ishiga e'tibor (bog'liqlik yaratmaydi).
- Testlanadigan — mock oson 8.11-bob — sifatli kod.
- Moslashuvchan — interface + DI (9: SOLID DIP) — almashtirish oson.
2. Nazariya — chuqur tushuntirish
2.1. Bog'liqlik (dependency) nima
Dependency (bog'liqlik) — bir class ishlashi uchun kerak bo'lgan boshqa class/obyekt:
class UserService {
// UserService ishlashi uchun Database KERAK Database — bog'liqlik
private db = new Database(); // o'zi yaratdi (qattiq bog'langan)
}Bog'liqlik — "menga ishlash uchun bu kerak".
UserServicegaDatabasekerak (bog'liqlik). Muammo:new Database()— qattiq bog'lanish (tight coupling — 2.2). DI buni hal qiladi 2.3-bob.
2.2. Qattiq bog'lanish muammosi (DI'siz)
// DI'siz — qattiq bog'lanish (tight coupling)
class UserService {
private db = new Database("postgres://..."); // o'zi yaratadi
}
class OrderService {
private db = new Database("postgres://..."); // yana yaratadi (takror!)
} Muammolar (DI'siz):
Takror (har joyda new Database)
Test qiyin (real DB'ni mock qilib bo'lmaydi — har joyda yangi)
O'zgartirish qiyin (DB sozlamasi o'zgarsa — har joyni)
Qattiq bog'lanish (UserService aniq Database'ga bog'liq)Qattiq bog'lanish — class o'z bog'liqligini o'zi yaratadi (
new). Bu — takror, test qiyin, o'zgartirish qiyin. DI bu muammoni hal qiladi (yaratish — tashqarida).
2.3. Dependency Injection (yechim)
DI — bog'liqlikni tashqaridan (constructor orqali) olish:
// DI — bog'liqlik tashqaridan (constructor)
@Injectable()
class UserService {
constructor(private db: Database) {} // Database TASHQARIDAN keladi (DI)
// UserService Database'ni YARATMAYDI — faqat oladi va ishlatadi
} DI bilan:
Takror yo'q (bitta Database — hammaga)
Test oson (mock Database berish)
O'zgartirish bir joyda (DB sozlamasi — bir marta)
Bo'sh bog'lanish (loose coupling)DI mohiyati: class bog'liqlikni so'raydi (constructor parametri), kimdir (IoC konteyner — 2.4) uni beradi. Class yaratish bilan band emas — o'z ishiga e'tibor. Bu — toza, testlanadigan, moslashuvchan kod (9: SOLID).
2.4. IoC (Inversion of Control) konteyner
IoC konteyner — bog'liqliklarni avtomatik yaratib, ulaydigan NestJS tizimi:
An'anaviy nazorat (siz boshqarasiz):
const db = new Database();
const service = new UserService(db); // SIZ yaratasiz, SIZ ulaysiz
const controller = new UserController(service);
Inversion of Control (konteyner boshqaradi):
NestJS bootstrap (8.1: 2.10) da BARCHA provider'larni yaratadi
Bog'liqliklarni TUR bo'yicha ulaydi (TS + reflect-metadata — 7.6)
Siz faqat constructor'da SO'RAYSIZ, konteyner BERADI
"Inversion" — yaratish nazorati SIZdan KONTEYNERga o'tdiIoC konteyner — NestJS'ning "miyasi": ilova ishga tushganda (bootstrap) barcha provider'larni yaratadi, bir-biriga ulaydi (dependency graph), va kerakli joyga beradi. Siz — faqat so'raysiz (
constructor); konteyner — hal qiladi. "Nazoratning teskari aylanishi" (yaratish — siz emas, konteyner).
2.5. DI qanday ishlaydi (under the hood — promptda yo'q)
1. @Injectable() — "bu class DI'da ishtirok etadi" (metama'lumot — 7.6)
2. emitDecoratorMetadata (tsconfig — 7.6: 2.3) — constructor parametr TURLARINI saqlaydi
3. reflect-metadata (7.6: 2.10) — "design:paramtypes" [Database, ...]
4. NestJS bootstrap'da: UserService'ni yaratish kerak
uning constructor turlarini o'qiydi ([Database])
Database'ni yaratadi (yoki mavjudini oladi) UserService'ga beradi
5. Singleton — bir marta yaratadi, qayta ishlatadi (2.13)DI sehir emas, mexanizm (under the hood): NestJS TS turlaridan (constructor parametr turlari — reflect-metadata orqali — 7.6) qaysi bog'liqlik kerakligini biladi.
constructor(private db: Database)NestJSDatabaseturini o'qiydi uni yaratib beradi. Shuning uchunemitDecoratorMetadata(7.6: 2.3) majburiy (turlarsiz DI ishlamaydi).
2.6. Provider va injection token
Har provider token bilan ro'yxatga olinadi (DI konteynerda kalit):
@Module({
providers: [UserService], // qisqa: token = class nomi (UserService)
})
// To'liq shakl (token aniq):
@Module({
providers: [
{ provide: UserService, useClass: UserService }, // provide — token; useClass — qiymat
],
})Injection token — DI konteynerda provider'ni topish uchun kalit. Qisqa shaklda (
providers: [UserService]) — token = class nomi. To'liq shaklda —provide(token) + qiymat (useClass/useValue/... — 2.7). Token class, string yoki Symbol bo'lishi mumkin 2.10-bob.
2.7. Custom provider turlari (4 ta — chuqur)
Standart providers: [Service] dan tashqari, 4 xil custom provider:
useClass — class instansiyasi (default; almashtirish mumkin)
useValue — tayyor qiymat (config, mock, konstanta)
useFactory — funksiya yaratadi (dinamik, async, bog'liqlik bilan)
useExisting — alias (mavjud provider'ga boshqa nom)Custom provider'lar — DI'ning to'liq kuchi: nafaqat class, balki qiymat (useValue — config), funksiya natijasi (useFactory — dinamik), alias (useExisting). Bu — NestJS ekotizimining (8.1: 2.17) asosi (TypeOrmModule, ConfigModule shularni ishlatadi).
2.8. useClass (class provider)
// useClass — token uchun class instansiyasi (almashtirish — 9: DIP)
@Module({
providers: [
{
provide: PaymentService, // token (interface/abstract)
useClass: process.env.NODE_ENV === "production"
? RealPaymentService // production — haqiqiy
: MockPaymentService, // dev — soxta (5.8)
},
],
})
// PaymentService inject qilinganda — muhitga qarab Real yoki Mock
useClass— token uchun class beradi (defaultproviders: [X]=useClass: X). Kuchi: implementatsiyani almashtirish (interface token, muhitga qarab class — 9: DIP). Test'da real o'rniga mock 8.11-bob. Bu — moslashuvchanlikning asosi.
2.9. useValue (qiymat provider)
// useValue — tayyor qiymat (config, konstanta, mock)
const config = { apiKey: "...", timeout: 5000 };
@Module({
providers: [
{ provide: "CONFIG", useValue: config }, // tayyor obyekt
{ provide: "API_KEY", useValue: process.env.KEY }, // konstanta (5.8)
],
})
// Inject (string token @Inject — 2.10)
@Injectable()
class Service {
constructor(@Inject("CONFIG") private config: any) {}
}
useValue— tayyor qiymat (class emas): konfiguratsiya, konstanta, tashqi kutubxona instansiyasi, yoki mock (test'da — 8.11). String token bo'lsa@Injectkerak 2.10-bob. Bu — qiymatlarni DI konteynerga qo'shish.
2.10. Injection token: class, string, Symbol
// 1. Class token (eng oddiy — @Inject kerak emas)
constructor(private service: UserService) {}
// 2. String token (@Inject kerak)
constructor(@Inject("CONFIG") private config: Config) {}
// 3. Symbol/konstanta token (typo'siz — tavsiya)
export const CONFIG = Symbol("CONFIG"); // yoki const CONFIG = "CONFIG"
constructor(@Inject(CONFIG) private config: Config) {}String token o'rniga konstanta/Symbol (best practices):
@Inject("CONFIG")— typo xavfi ("CONIFG"— topilmaydi). Konstanta (const CONFIG_TOKEN = "CONFIG") yoki Symbol — typo'siz, IDE yordami. Class token — eng oddiy (@Injectkerak emas — tur bo'yicha). Interface token bo'lolmaydi (runtime'da yo'q — 7.1: 2.4) string/Symbol/abstract class.
2.11. useFactory (dinamik provider)
// useFactory — funksiya yaratadi (dinamik, async, bog'liqlik bilan)
@Module({
providers: [
{
provide: "DATABASE",
useFactory: async (config: ConfigService) => { // bog'liqlik (inject)
const db = await connectDB(config.get("DB_URL")); // async!
return db;
},
inject: [ConfigService], // factory'ga inject (2.11)
},
],
})
useFactory— eng kuchli custom provider: funksiya provider'ni yaratadi. Dinamik (shartga qarab), async (DB ulanish — 8.3), bog'liqlik bilan (inject— factory'ga boshqa provider). NestJS ekotizimi (forRoot — 8.1: 2.13) ko'pincha useFactory ishlatadi.
2.12. useExisting (alias)
// useExisting — mavjud provider'ga boshqa nom (alias — bir instansiya)
@Module({
providers: [
LoggerService,
{ provide: "AppLogger", useExisting: LoggerService }, // alias
],
})
// "AppLogger" va LoggerService — BIR XIL instansiya (useClass yangisini yaratardi)
useExisting— mavjud provider'ga ikkinchi nom (alias).useClassdan farqi: yangi instansiya yaratmaydi — mavjudini ko'rsatadi (singleton). Eski API moslik, yoki bir provider'ga turli token. Kamdan-kam, lekin foydali.
2.13. Provider scope (lifetime — chuqur)
Scope — provider qancha yashashi (8.1: 2.14 — bu yerda chuqur):
DEFAULT (Singleton):
- Bootstrap'da BIR MARTA yaratiladi
- Butun ilovada BIR instansiya (hamma ishlatadi)
- Eng tez, eng ko'p ishlatiladi
REQUEST:
- Har HTTP so'rovga YANGI instansiya
- Shu so'rovdagi hamma service bir instansiyani ulashadi
- So'rovga xos ma'lumot (request user, request logger — 5.12)
- SEKINROQ (har so'rovda yaratish)
TRANSIENT:
- Har INJECT'ga yangi instansiya (ulashmaydi)
- Kamdan-kam (har joyda alohida holat kerak bo'lganda)@Injectable({ scope: Scope.REQUEST }) // har so'rovga yangi
export class RequestScopedService {}Scope tanlovi: Singleton (default) — 95% holat (tez, holatsiz service). REQUEST — so'rovga xos kontekst (joriy foydalanuvchi, correlation ID — 5.12); lekin sekinroq (har so'rovda yaratish + butun zanjir request-scoped bo'ladi). TRANSIENT — har inject alohida. Default'da qoling; REQUEST — faqat zarur bo'lganda.
2.14. Scope bubbling (muhim nuans — promptda yo'q)
Scope "yuqoriga ko'tariladi": agar provider REQUEST-scoped bo'lsa, uni ishlatadigan hamma ham REQUEST bo'ladi:
Controller Service A (REQUEST) ...
Controller ham REQUEST bo'ladi (scope bubbling)
butun zanjir REQUEST (sekinroq)
REQUEST/TRANSIENT'ni Singleton'ga inject qilib BO'LMAYDI
(singleton bir marta yaratiladi — request'ni qayerdan oladi?)
RuntimeExceptionScope bubbling (best practices): REQUEST-scoped provider ishlatadigan zanjir — butunlay REQUEST bo'ladi (performance ta'siri). Va REQUEST'ni singleton'ga inject qilib bo'lmaydi (xato). Aralash kerak bo'lsa — useFactory yoki
REQUESTtoken 8.2-bob. Bu — DI'ning nozik, lekin muhim tomoni.
2.15. Property vs constructor injection
// Constructor injection (TAVSIYA)
@Injectable()
class Service {
constructor(private db: Database) {} // hamma bog'liqlik yaratishda mavjud
}
// Property injection (kamdan-kam — faqat optional/circular)
@Injectable()
class Service {
@Inject(Database) private db: Database; // xususiyatga
}Constructor injection afzal (best practices): hamma bog'liqlik obyekt yaratilganda mavjud (kutilmagan runtime xato kam); aniq (constructor — bog'liqliklar ro'yxati); test oson. Property injection — faqat maxsus holat (ixtiyoriy bog'liqlik, ba'zi circular — 2.16).
2.16. Circular dependency va forwardRef
Circular dependency — ikki provider/modul bir-birini ishlatadi (aylana):
// A B, B A (aylana — NestJS hal qila olmaydi)
@Injectable()
class UserService {
constructor(private orderService: OrderService) {} // A B
}
@Injectable()
class OrderService {
constructor(private userService: UserService) {} // B A (aylana!)
}
// Yechim: forwardRef (kechiktirilgan hal qilish)
@Injectable()
class UserService {
constructor(@Inject(forwardRef(() => OrderService)) private orderService: OrderService) {}
}Circular dependency — A B'ga, B A'ga bog'liq (NestJS qaysidan boshlashni bilmaydi).
forwardRef(() => X)— "bu bog'liqlikni keyinroq hal qil" (kechiktirilgan). Lekin — circular — ko'pincha dizayn xatosi (9): uchinchi service'ga ajratish yoki event ishlatish afzal. forwardRef — oxirgi chora.
2.17. DI va testlanadigan kod (8.11 ko'prik)
DI'ning eng katta foydasi — test 8.11-bob:
// DI tufayli test'da real DB o'rniga MOCK (8.11)
const moduleRef = await Test.createTestingModule({
providers: [
UserService,
{ provide: Database, useValue: mockDatabase }, // mock! (useValue — 2.9)
],
}).compile();
const service = moduleRef.get(UserService);
// service real Database o'rniga mockDatabase ishlatadi (test izolyatsiyasi)DI = testlanadigan kod: DI tufayli test'da real bog'liqlik (DB, email) o'rniga mock beramiz (
useValue— 2.9). UserService o'zgarmaydi — faqat unga boshqa Database beriladi (DI). Bu — unit test'ning asosi 8.11-bob. DI'siz — bu juda qiyin (real DB kerak).
2.18. DI va SOLID (DIP — 9 ko'prik)
// Interface (abstraksiya) — 9: Dependency Inversion Principle
interface IPaymentGateway {
charge(amount: number): Promise<boolean>;
}
@Injectable()
class OrderService {
constructor(
@Inject("PAYMENT") private payment: IPaymentGateway, // INTERFACE'ga bog'liq
) {}
}
@Module({
providers: [
{ provide: "PAYMENT", useClass: StripeGateway }, // implementatsiya (almashtirsa bo'ladi)
],
})DI + interface = DIP (9: SOLID): yuqori daraja (OrderService) interfacega bog'liq (aniq class'ga emas). Implementatsiya (Stripe/Payme) — DI orqali beriladi (almashtirsa bo'ladi). Bu — toza arxitektura (9). Interface runtime'da yo'q 7.1-bob string/abstract class token 2.10-bob.
2.19. @Optional() — ixtiyoriy bog'liqlik
Odatda bog'liqlik majburiy: provider topilmasa — NestJS xato beradi (6: 1-xato). Ba'zan bog'liqlik ixtiyoriy bo'lishi kerak (bo'lsa ishlat, bo'lmasa — undefined):
import { Injectable, Optional, Inject } from "@nestjs/common";
@Injectable()
export class HttpClient {
// @Optional() — provider topilmasa xato EMAS, faqat undefined
constructor(
@Optional() @Inject("HTTP_OPTIONS") private options?: HttpOptions,
) {
this.options = options ?? { timeout: 5000 }; // default (bo'lmasa)
}
}
@Optional()— bog'liqlikni ixtiyoriy qiladi: DI konteyner uni topa olmasa, xato o'rnigaundefinedberadi (siz default qo'yasiz). Ko'proq qayta ishlatiladigan kutubxona/modullarda foydali (foydalanuvchi config bermasligi mumkin). Odatiy service'da — majburiy bog'liqlik afzal (yetishmasa darrov xato — 6: 1-xato).@Optional()@Inject()bilan birga (yoki class token uchun yolg'iz) ishlatiladi.
2.20. ModuleRef — dasturiy (imperative) DI
Odatda bog'liqlik constructor orqali deklarativ olinadi. Ba'zan provider'ni kod ichida, dinamik (ish vaqtida) olish kerak — buning uchun ModuleRef:
import { Injectable, OnModuleInit } from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";
@Injectable()
export class TaskRunner implements OnModuleInit {
private handler: HandlerService;
constructor(private moduleRef: ModuleRef) {} // ModuleRef inject (o'zi mavjud)
onModuleInit() {
// get — SINGLETON/mavjud instansiyani oladi (sinxron)
this.handler = this.moduleRef.get(HandlerService, { strict: false });
}
async run() {
// resolve — SCOPED (REQUEST/TRANSIENT) provider uchun YANGI instansiya (async)
const scoped = await this.moduleRef.resolve(ScopedService);
scoped.doWork();
}
}
ModuleRef— dasturiy DI: konteyner bilan kod ichida ishlash imkoni.get(Token)— mavjud (singleton) provider'ni sinxron oladi ({ strict: false }— butun ilovadan izlaydi, faqat joriy modul emas).resolve(Token)— scoped (REQUEST/TRANSIENT — 2.13) provider'ning yangi instansiyasiniPromisebilan qaytaradi. Qachon kerak: dinamik handler tanlash (strategy — token ish vaqtida ma'lum), plagin tizimi, yoki ba'zi circular holatlar (2.16 forwardRef muqobili). Odatda constructor injection afzal — ModuleRef faqat dinamik zarurat bo'lganda.
2.21. Dynamic module (register / forRoot / forFeature naqshi)
Odatiy modul statik (@Module({...}) — o'zgarmas). Dinamik modul — konfiguratsiya bilan sozlanadigan modul: chaqirilganda parametr qabul qiladi va provider'larni shu parametrga qarab yaratadi. Bu — NestJS ekotizimining (ConfigModule.forRoot(), TypeOrmModule.forRoot(), JwtModule.register() — 8.1: 2.17) asosidagi naqsh:
import { DynamicModule, Module } from "@nestjs/common";
export const CONFIG_OPTIONS = Symbol("CONFIG_OPTIONS");
interface ConfigModuleOptions { folder: string; }
@Module({})
export class ConfigModule {
// register / forRoot — SINXRON sozlash (parametr provider)
static forRoot(options: ConfigModuleOptions): DynamicModule {
return {
module: ConfigModule,
providers: [
{ provide: CONFIG_OPTIONS, useValue: options }, // parametrni provider'ga
ConfigService,
],
exports: [ConfigService],
global: true, // ixtiyoriy: global modul (har joyda import'siz — 8.1)
};
}
}
// Ishlatish (root modulda):
@Module({
imports: [ConfigModule.forRoot({ folder: "./config" })], // parametr bilan
})
export class AppModule {}Dinamik modul (naqsh): metod (
forRoot/register/forFeature)DynamicModuleobyekt qaytaradi (module+providers/imports/exports). Konvensiya:forRoot/forRootAsync— ilova bo'yicha bir marta global sozlash (DB, config);register/registerAsync— har import'da alohida sozlash (masalan,HttpModule.register({...}));forFeature— modulning bir qismini (feature) ro'yxatga olish (TypeOrmModule.forFeature([User])— 8.3). Parametrni provider'ga aylantirib (useValue), modul ichidagi service uni inject qiladi (@Inject(CONFIG_OPTIONS)).
2.22. forRootAsync / registerAsync (async sozlash)
Sozlash qiymati ish vaqtida, boshqa provider'dan kelsa (masalan, ConfigServicedan DB URL) — async variant kerak. U useFactory + inject ishlatadi 2.11-bob:
export class DatabaseModule {
// forRootAsync — sozlash boshqa provider'ga bog'liq (useFactory + inject)
static forRootAsync(): DynamicModule {
return {
module: DatabaseModule,
imports: [ConfigModule], // ConfigService kerak
providers: [
{
provide: "DB_CONNECTION",
useFactory: async (config: ConfigService) => { // async factory (2.11)
return await createConnection(config.get("DB_URL"));
},
inject: [ConfigService], // factory bog'liqligi
},
],
exports: ["DB_CONNECTION"],
};
}
}
// Ishlatish:
@Module({ imports: [DatabaseModule.forRootAsync()] })
export class AppModule {}
forRootAsync/registerAsync: sozlash qiymati statik emas — u boshqa provider (ConfigService), tashqi manba yokiPromisedan keladi. Yechim:useFactory2.11-bob +inject. Ekotizim modullari (TypeOrmModule.forRootAsync,JwtModule.registerAsync) shu naqshniuseFactory(yokiuseClass/useExistingbilanoptionsFactory) sifatida taklif qiladi. Bu — DI'ning kutubxona darajasidagi eng kuchli ko'rinishi (dinamik modul + async provider birga).
2.23. Async provider (useFactory + Promise)
Provider'ning o'zi asinxron yaratilishi mumkin (DB ulanish, tashqi resurs). useFactory async/Promise qaytarsa — NestJS ulanishni kutadi, keyin ilovani ishga tushiradi:
{
provide: "ASYNC_CONNECTION",
useFactory: async (): Promise<Connection> => {
const conn = await createConnection(); // NestJS bu Promise'ni KUTADI
return conn; // faqat ulangach — inject tayyor
},
}
// Ilova bootstrap'i shu async provider tayyor bo'lguncha KUTADI
// (ya'ni DB ulanmaguncha ilova so'rov qabul qilmaydi — xavfsiz)Async provider:
useFactoryPromise(yokiasync) qaytarsa, NestJS hal bo'lishini kutadi va hal qilingan qiymatni inject qiladi (Promise'ni emas). Foydasi: ilova faqat bog'liqlik (DB, cache) tayyor bo'lgach so'rov qabul qiladi (yarim-tayyor holatda emas). Bu — 8.3 (DB ulanish) va cache (Redis — 5.21) uchun asosiy naqsh.
2.24. DI konteyner ichki ishlashi (chuqurroq — under the hood)
2.5'da qisqacha ko'rdik; endi qadamma-qadam:
1. TARANG (scan): NestJS bootstrap'da barcha modullarni o'qiydi,
har modul providers/imports/exports'ini yig'adi (metama'lumot — 7.6).
2. TOKEN PROVIDER xaritasi: har token uchun qanday yaratishni belgilaydi
(useClass/useValue/useFactory/useExisting — 2.7). Bu — "provider registri".
3. BOG'LIQLIK GRAFI: har provider constructor turlarini o'qiydi
(design:paramtypes — reflect-metadata — 7.6) kim kimga bog'liq.
4. TOPOLOGIK TARTIB: grafni tartiblaydi (bog'liqligi yo'qdan boshlab).
Circular bo'lsa — aniqlaydi (6: 3-xato) yoki forwardRef kutadi 2.16-bob.
5. INSTANSIYALASH: tartib bo'yicha yaratadi. Har token uchun:
- useValue qiymatni oladi (yaratmaydi)
- useClass new Class(...bog'liqliklar)
- useFactory factory(...inject) (async bo'lsa — kutadi — 2.23)
- Singleton keshlaydi 2.13-bob; qayta so'ralsa — o'sha instansiya
6. INJECT: yaratilgan instansiyalarni constructor'larga uzatadi.
Ilova tayyor — so'rovlarni qabul qiladi.DI konteyner (mohiyat): konteyner — bu token provider registri + bog'liqlik grafi + instansiya keshi (singleton uchun). Bootstrap'da grafni topologik tartiblab (bog'liqligi yo'qidan boshlab) instansiyalaydi. Shuning uchun circular muammo (graf aylanasi — qayerdan boshlash noaniq — 2.16), va shuning uchun turlar majburiy (graf turlardan quriladi —
emitDecoratorMetadata— 2.5, 7.6). REQUEST-scoped provider'lar bootstrap'da emas, har so'rovda yaratiladi 2.13-bob — shuning uchun sekinroq. Bu manzarani tushunish — DI xatolarini (6) darrov hal qilishning kaliti.
2.25. Best practices (DI)
Constructor injection (property emas — 2.15)
Default singleton scope (REQUEST/TRANSIENT ehtiyot — 2.13, 2.14)
Custom provider'lar (useValue config, useFactory dinamik — 2.7)
Token: konstanta/Symbol (string typo — 2.10)
Interface + useClass (DIP — almashtirish/test — 2.8, 2.18)
Circular dependency — qayta dizayn (forwardRef oxirgi chora — 2.16)
REQUEST'ni singleton'ga inject qilmang 2.14-bob
DI mock (testlanadigan — 2.17, 8.11)
@Optional() — faqat haqiqiy ixtiyoriy bog'liqlik 2.19-bob
ModuleRef — faqat dinamik zarurat (deklarativ DI afzal — 2.20)
Dynamic module: forRoot (global) / register (har import) / forFeature 2.21-bob
Async sozlash forRootAsync (useFactory + inject — 2.22)
Async provider — DB/cache tayyor bo'lgach ilova (2.23)3. Sintaksis — tez ma'lumotnoma
// Oddiy DI (2.3)
@Injectable() class Service { constructor(private dep: OtherService) {} }
// Custom provider'lar (2.7-2.12)
{ provide: TOKEN, useClass: X } // class
{ provide: TOKEN, useValue: qiymat } // qiymat
{ provide: TOKEN, useFactory: (dep) => {...}, inject: [Dep] } // factory
{ provide: TOKEN, useExisting: X } // alias
// Token (2.10)
@Inject("STRING_TOKEN") yoki @Inject(SYMBOL_TOKEN)
// Scope 2.13-bob: @Injectable({ scope: Scope.REQUEST })
// Circular 2.16-bob: @Inject(forwardRef(() => X))
// Ixtiyoriy (2.19)
constructor(@Optional() @Inject(TOKEN) private x?: T) {}
// ModuleRef — dasturiy DI (2.20)
constructor(private moduleRef: ModuleRef) {}
this.moduleRef.get(Service, { strict: false }); // singleton (sinxron)
await this.moduleRef.resolve(ScopedService); // scoped (async)
// Dynamic module (2.21, 2.22)
static forRoot(opts): DynamicModule { return { module: X, providers: [...], exports: [...] }; }
static forRootAsync(): DynamicModule { /* useFactory + inject */ }4. Batafsil kod namunalari
Misol 1 — DI'siz vs DI bilan (2.2, 2.3)
// DI'siz — qattiq bog'lanish (2.2)
class UserService {
private db = new Database("postgres://..."); // o'zi yaratadi
private email = new EmailService(); // yana yaratadi
// test: real DB/email kerak (qiyin); o'zgartirish: har joyni
}
// DI bilan — bo'sh bog'lanish (2.3)
@Injectable()
class UserService {
constructor(
private db: Database, // tashqaridan (DI)
private email: EmailService, // tashqaridan
) {}
// test: mock berish oson; bir instansiya hammaga; toza
}Misol 2 — Standart DI (8.1 takrori — 2.3)
@Injectable()
export class EmailService { // (5.19)
yubor(to: string, matn: string) { /* ... */ }
}
@Injectable()
export class UsersService {
constructor(private emailService: EmailService) {} // DI (NestJS o'zi beradi)
async yarat(dto: CreateUserDto) {
const user = { id: 1, ...dto };
await this.emailService.yubor(user.email, "Xush kelibsiz!"); // boshqa service
return user;
}
}
@Module({
providers: [UsersService, EmailService], // ikkalasi ro'yxatda (2.6)
})
export class UsersModule {}Misol 3 — useValue (config, konstanta — 2.9)
// Konfiguratsiya provider (useValue — 2.9)
export const APP_CONFIG = Symbol("APP_CONFIG"); // token (Symbol — 2.10)
interface AppConfig { apiKey: string; timeout: number; }
@Module({
providers: [
{
provide: APP_CONFIG,
useValue: { apiKey: process.env.API_KEY, timeout: 5000 } as AppConfig, // (5.8)
},
],
exports: [APP_CONFIG],
})
export class ConfigModule {}
// Inject
@Injectable()
export class ApiService {
constructor(@Inject(APP_CONFIG) private config: AppConfig) {} // (2.10)
sorov() { console.log(this.config.apiKey); }
}Misol 4 — useFactory (dinamik, async — 2.11)
// DB ulanish factory (async, bog'liqlik bilan — 2.11)
import { ConfigService } from "@nestjs/config"; // (8.14)
export const DATABASE = Symbol("DATABASE");
@Module({
providers: [
{
provide: DATABASE,
useFactory: async (config: ConfigService) => { // factory + inject
const db = await createConnection({ // async (8.3)
url: config.get("DATABASE_URL"),
});
return db;
},
inject: [ConfigService], // factory bog'liqligi
},
],
exports: [DATABASE],
})
export class DatabaseModule {}Misol 5 — useClass (almashtirish — DIP — 2.8, 2.18)
// Interface (abstraksiya — 9: DIP)
export interface IPaymentGateway {
charge(amount: number, card: string): Promise<{ success: boolean }>;
}
export const PAYMENT_GATEWAY = Symbol("PAYMENT_GATEWAY");
// Ikki implementatsiya
@Injectable()
export class StripeGateway implements IPaymentGateway {
async charge(amount: number, card: string) { return { success: true }; }
}
@Injectable()
export class MockGateway implements IPaymentGateway { // test/dev (8.11)
async charge() { return { success: true }; }
}
// Muhitga qarab tanlash (useClass — 2.8)
@Module({
providers: [
{
provide: PAYMENT_GATEWAY,
useClass: process.env.NODE_ENV === "production" ? StripeGateway : MockGateway,
},
],
})
export class PaymentModule {}
// OrderService interface'ga bog'liq (almashtirsa bo'ladi — DIP)
@Injectable()
export class OrderService {
constructor(@Inject(PAYMENT_GATEWAY) private payment: IPaymentGateway) {}
}Misol 6 — Scope: REQUEST (so'rovga xos — 2.13)
import { Injectable, Scope, Inject } from "@nestjs/common";
import { REQUEST } from "@nestjs/core";
import { Request } from "express";
// Har so'rovga yangi (so'rovga xos kontekst — 2.13)
@Injectable({ scope: Scope.REQUEST })
export class RequestLogger {
constructor(@Inject(REQUEST) private req: Request) {} // joriy so'rov
log(xabar: string) {
console.log(`[${this.req.method} ${this.req.url}] ${xabar}`); // (5.12)
}
}
// Bu service'ni ishlatadigan zanjir REQUEST bo'ladi (bubbling — 2.14)Misol 7 — forwardRef (circular — 2.16)
import { Injectable, Inject, forwardRef } from "@nestjs/common";
@Injectable()
export class UserService {
constructor(
@Inject(forwardRef(() => OrderService)) // kechiktirilgan (circular — 2.16)
private orderService: OrderService,
) {}
}
@Injectable()
export class OrderService {
constructor(
@Inject(forwardRef(() => UserService))
private userService: UserService,
) {}
}
// Yaxshiroq: circular'ni QAYTA DIZAYN qiling (uchinchi service yoki event — 2.16, 9)Misol 8 — DI bilan test (mock — 2.17, 8.11)
import { Test } from "@nestjs/testing";
describe("UsersService", () => {
let service: UsersService;
const mockEmail = { yubor: jest.fn() }; // mock (8.11)
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
UsersService,
{ provide: EmailService, useValue: mockEmail }, // real o'rniga mock (2.9, 2.17)
],
}).compile();
service = moduleRef.get(UsersService);
});
it("yangi user yaratganda email yuboradi", async () => {
await service.yarat({ ism: "Ali", email: "ali@a.uz" });
expect(mockEmail.yubor).toHaveBeenCalled(); // mock tekshiruvi
});
});
// DI tufayli — real email o'rniga mock (test izolyatsiyasi — 8.11)Misol 9 — Repository pattern + DI (9: Clean Architecture)
// Interface (abstraksiya — 9: DIP)
export interface IUserRepository {
topId(id: number): Promise<User | null>;
saqla(user: User): Promise<User>;
}
export const USER_REPOSITORY = Symbol("USER_REPOSITORY");
// Implementatsiya (TypeORM — 8.3)
@Injectable()
export class TypeOrmUserRepository implements IUserRepository {
async topId(id: number) { /* TypeORM 8.3-bob */ return null; }
async saqla(user: User) { return user; }
}
// Service interface'ga bog'liq (DB texnologiyasini bilmaydi — 9)
@Injectable()
export class UsersService {
constructor(@Inject(USER_REPOSITORY) private repo: IUserRepository) {}
topId(id: number) { return this.repo.topId(id); }
}
@Module({
providers: [
UsersService,
{ provide: USER_REPOSITORY, useClass: TypeOrmUserRepository }, // almashtirsa bo'ladi
],
})
export class UsersModule {}
// Mongoose'ga o'tsangiz — faqat useClass'ni almashtirasiz (service o'zgarmaydi — DIP)Misol 10 — Bir nechta provider birga (real modul)
@Module({
imports: [ConfigModule], // boshqa modul (2.6)
controllers: [UsersController],
providers: [
UsersService, // useClass (default)
EmailService,
{ provide: USER_REPOSITORY, useClass: TypeOrmUserRepository }, // interface
{
provide: "CACHE", // string token
useFactory: (config: ConfigService) => new Redis(config.get("REDIS_URL")), // (5.21)
inject: [ConfigService],
},
],
exports: [UsersService], // ulashish (2.6)
})
export class UsersModule {}Misol 11 — @Optional() + useExisting (ixtiyoriy + alias — 2.19, 2.12)
import { Injectable, Optional, Inject, Module } from "@nestjs/common";
// Ixtiyoriy config bilan qayta ishlatiladigan service (2.19)
@Injectable()
export class CacheClient {
private ttl: number;
constructor(
@Optional() @Inject("CACHE_OPTIONS") options?: { ttl?: number }, // ixtiyoriy
) {
this.ttl = options?.ttl ?? 60; // provider yo'q bo'lsa — default (undefined)
}
}
@Injectable()
export class LoggerService {
log(m: string) { console.log(m); }
}
@Module({
providers: [
CacheClient, // CACHE_OPTIONS bermadik — @Optional ishlaydi
LoggerService,
{ provide: "AppLogger", useExisting: LoggerService }, // alias — BIR instansiya (2.12)
],
})
export class InfraModule {}
// "AppLogger" va LoggerService — bir xil obyekt (useExisting — 2.12)Misol 12 — ModuleRef: dinamik strategiya tanlash (2.20)
import { Injectable, OnModuleInit } from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";
// Har provayder (Stripe/Payme) — alohida strategiya service
@Injectable() export class StripeStrategy { pay() { /* ... */ } }
@Injectable() export class PaymeStrategy { pay() { /* ... */ } }
@Injectable()
export class PaymentRouter implements OnModuleInit {
private strategies = new Map<string, StripeStrategy | PaymeStrategy>();
constructor(private moduleRef: ModuleRef) {} // ModuleRef (2.20)
onModuleInit() {
// Token ish vaqtida ma'lum — get bilan dinamik olamiz
this.strategies.set("stripe", this.moduleRef.get(StripeStrategy));
this.strategies.set("payme", this.moduleRef.get(PaymeStrategy));
}
pay(provider: string) {
this.strategies.get(provider)?.pay(); // dinamik tanlash
}
}
@Module({ providers: [PaymentRouter, StripeStrategy, PaymeStrategy] })
export class PaymentModule {}Misol 13 — Dynamic module: forRoot + forRootAsync (2.21, 2.22)
import { DynamicModule, Module, Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config"; // (8.14)
export const STORAGE_OPTIONS = Symbol("STORAGE_OPTIONS");
interface StorageOptions { bucket: string; }
@Injectable()
export class StorageService {
constructor(@Inject(STORAGE_OPTIONS) private opts: StorageOptions) {}
bucket() { return this.opts.bucket; }
}
@Module({})
export class StorageModule {
// Sinxron sozlash (2.21)
static forRoot(options: StorageOptions): DynamicModule {
return {
module: StorageModule,
providers: [
{ provide: STORAGE_OPTIONS, useValue: options }, // parametr provider
StorageService,
],
exports: [StorageService],
global: true,
};
}
// Async sozlash — qiymat ConfigService'dan (2.22)
static forRootAsync(): DynamicModule {
return {
module: StorageModule,
imports: [ConfigModule],
providers: [
{
provide: STORAGE_OPTIONS,
useFactory: (config: ConfigService) => ({ // dinamik (2.11)
bucket: config.get("STORAGE_BUCKET"),
}),
inject: [ConfigService],
},
StorageService,
],
exports: [StorageService],
};
}
}
// Ishlatish:
@Module({
imports: [
StorageModule.forRoot({ bucket: "static" }), // sinxron
// yoki: StorageModule.forRootAsync(), // async (ENV'dan)
],
})
export class AppModule {}5. To'g'ri va noto'g'ri holatlar
1) new bilan yaratish (DI o'rniga)
// qattiq bog'lanish (2.2)
class Service { private db = new Database(); }
// DI (constructor)
@Injectable() class Service { constructor(private db: Database) {} }2) Property injection (constructor o'rniga)
// property (kutilmagan xato — 2.15)
@Inject(Database) private db: Database;
// constructor
constructor(private db: Database) {}3) String token (typo xavfi)
// string (typo — 2.10)
@Inject("DATABSE") // typo!
// konstanta/Symbol
@Inject(DATABASE_TOKEN)4) REQUEST scope'ni keraksiz ishlatish
hamma service REQUEST (sekin — bubbling — 2.14)
default singleton (REQUEST faqat so'rovga xos kontekst — 2.13)5) Circular dependency (dizayn xatosi)
AB circular forwardRef (murakkab — 2.16)
qayta dizayn (uchinchi service, event — 9)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Nest can't resolve dependencies of X (?)
Sababi: bog'liqlik provider'da yo'q, yoki modul import qilinmagan 2.6-bob. Yechimi: providers'ga qo'sh; boshqa moduldan bo'lsa — exports + imports; ? — qaysi parametr yetishmasligini ko'rsatadi.
Xato 2 — Cannot resolve ... reflect-metadata
Sababi: emitDecoratorMetadata yoki @Injectable yo'q (2.5, 7.6). Yechimi: tsconfig; @Injectable.
Xato 3 — Circular dependency detected
Sababi: AB aylana 2.16-bob. Yechimi: forwardRef; yoki qayta dizayn (afzal — 9).
Xato 4 — RuntimeException: scope mismatch
Sababi: REQUEST'ni singleton'ga inject 2.14-bob. Yechimi: scope'larni moslash; useFactory; REQUEST zanjirini cheklash.
Xato 5 — String token topilmadi
Sababi: token typo, yoki provider yo'q 2.10-bob. Yechimi: konstanta/Symbol token; provider ro'yxatda.
Xato 6 — useFactory bog'liqlik undefined
Sababi: inject array'da bog'liqlik yo'q 2.11-bob. Yechimi: inject: [Dep] qo'shing.
Xato 7 — moduleRef.get() scoped provider'da xato
Sababi: get() faqat singleton/mavjud instansiya uchun; REQUEST/TRANSIENT'da ishlamaydi 2.20-bob. Yechimi: scoped uchun await moduleRef.resolve(Token) ishlating.
Xato 8 — moduleRef.get() boshqa moduldan topmadi
Sababi: default get() faqat joriy modul kontekstida izlaydi 2.20-bob. Yechimi: moduleRef.get(Token, { strict: false }) — butun ilovadan izlaydi.
Xato 9 — Dynamic module provider export qilinmagan
Sababi: forRoot exportsida provider yo'q — import qilgan modul uni ko'rmaydi 2.21-bob. Yechimi: DynamicModule.exportsga qo'shing.
Xato 10 — forRootAsync'da inject yo'q factory bog'liqligi undefined
Sababi: async sozlashda useFactory bog'liqligi inject array'da yo'q, yoki kerakli modul importsda emas 2.22-bob. Yechimi: imports: [ConfigModule] + inject: [ConfigService].
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- NestJS arxitektura 8.1-bob: DI — uchlikning bog'lovchisi.
- Decorators 7.6-bob: @Injectable, @Inject, reflect-metadata.
- TypeScript (7): turlar — DI asosi (paramtypes).
- DB 8.3-bob: repository DI; useFactory ulanish.
- Config 8.14-bob: ConfigService DI; useValue;
ConfigModule.forRoot(dinamik modul — 2.21). - Dinamik modul (8.1: 2.17): forRoot/register/forFeature — DI'ning kutubxona darajasi (2.21, 2.22).
- Testing 8.11-bob: DI mock;
moduleRef.get/resolvetest'da 2.20-bob. - SOLID (9): DIP — interface + DI.
- Clean architecture (9): repository pattern + DI.
- Barcha NestJS (8): DI hamma joyda.
8. Eng yaxshi amaliyotlar (best practices)
- Constructor injection (property emas — 2.15).
- Default singleton (REQUEST/TRANSIENT ehtiyot — bubbling — 2.13, 2.14).
- Custom provider'lar (useValue config, useFactory dinamik/async — 2.7).
- Token: konstanta/Symbol (string typo'siz — 2.10).
- Interface + useClass (DIP — almashtirish/test — 2.8, 2.18).
- Circular — qayta dizayn (forwardRef oxirgi chora — 2.16).
- REQUEST'ni singleton'ga inject qilmang 2.14-bob.
- DI mock (testlanadigan — 2.17, 8.11).
- Repository pattern + DI (DB abstraksiyasi — Misol 9, 9).
- @Optional() faqat haqiqiy ixtiyoriy bog'liqlikda 2.19-bob.
- ModuleRef faqat dinamik zaruratda (deklarativ constructor injection afzal — 2.20).
- Dinamik modul naqshi: forRoot (global bir marta) / register (har import) / forFeature (2.21, 2.22).
- Async sozlash forRootAsync — useFactory + inject 2.22-bob.
- DI'ni tushun (sehir emas — reflect-metadata + bog'liqlik grafi mexanizmi — 2.5, 2.24).
9. Amaliy loyiha: "DI bilan Moslashuvchan Arxitektura"
Dependency Injection'ni chuqur mustahkamlash.
Maqsad
DI'ning to'liq kuchini ishlatib, moslashuvchan, testlanadigan arxitektura qurish: custom provider'lar, interface + DI (DIP), va mock bilan test.
Talablar (requirements)
- Standart DI: service'lar bir-biriga inject (Misol 2, 2.3).
- useValue: config provider (Symbol token — Misol 3, 2.9).
- useFactory: dinamik/async (DB yoki Redis ulanish — Misol 4, 10, 2.11).
- useClass + interface: payment gateway (muhitga qarab — DIP — Misol 5, 2.8, 2.18).
- Repository pattern: interface + DI (DB abstraksiyasi — Misol 9, 9).
- Token: Symbol/konstanta (string emas — 2.10).
- Scope: REQUEST service (so'rovga xos — Misol 6, 2.13).
- Test: mock bilan (useValue — Misol 8, 2.17).
- (Bonus) Circular: forwardRef yoki qayta dizayn 2.16-bob.
- Almashtirish: implementatsiyani o'zgartiring (service o'zgarmasligini ko'rsating — DIP).
- (Bonus) Dinamik modul:
forRootbilan sozlanadigan modul (Misol 13, 2.21). - (Bonus) forRootAsync: ENV'dan async sozlash (useFactory + inject — 2.22).
- (Bonus) ModuleRef: dinamik strategiya tanlash (Misol 12, 2.20).
- (Bonus) @Optional(): ixtiyoriy bog'liqlik + default (Misol 11, 2.19).
Maslahatlar (hint)
- Constructor injection (2.15, 2-xato).
- Token: Symbol (string typo — 2.10, 3-xato).
- useFactory: inject array (2.11, 6-xato).
- Interface token: Symbol/abstract (runtime yo'q — 2.10, 2.18).
- Test: useValue mock (2.17, Misol 8).
- REQUEST ehtiyot (bubbling — 2.14).
"Tayyor" mezonlari (acceptance criteria)
- Standart DI (service inject).
- useValue (config, Symbol token).
- useFactory (async/dinamik).
- useClass + interface (DIP, almashtirish).
- Repository pattern (interface + DI).
- Token Symbol/konstanta.
- REQUEST scope service.
- Mock bilan test.
- (Bonus) Circular yechimi.
- Implementatsiya almashtirish (service o'zgarmaydi).
- (Bonus) Dinamik modul (forRoot).
- (Bonus) forRootAsync (async sozlash).
- (Bonus) ModuleRef (dinamik olish).
- (Bonus) @Optional() (ixtiyoriy bog'liqlik).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda NestJS'ning yuragini — Dependency Injection ni — chuqur o'rgandik:
- Bog'liqlik 2.1-bob; qattiq bog'lanish muammosi (2.2) DI yechimi (tashqaridan — 2.3).
- IoC konteyner (avtomatik yaratish/ulash — 2.4); under the hood (reflect-metadata, paramtypes — 2.5); token (2.6, 2.10).
- Custom provider'lar: useClass (almashtirish — 2.8), useValue (qiymat — 2.9), useFactory (dinamik/async — 2.11), useExisting (alias — 2.12).
- Scope (singleton/request/transient — 2.13); bubbling 2.14-bob; constructor injection 2.15-bob; circular/forwardRef 2.16-bob; DI = testlanadigan + DIP (2.17, 2.18).
- @Optional() (ixtiyoriy bog'liqlik — 2.19); ModuleRef (dasturiy DI — get/resolve — 2.20); dinamik modul (forRoot/register/forFeature — 2.21), forRootAsync 2.22-bob, async provider 2.23-bob; DI konteyner ichki ishlashi (registri + graf + kesh — 2.24).
Keyingi bob — 8.3-bob: DB ulanish — TypeORM / Prisma / Mongoose bilan. Arxitektura va DI'ni bildik; endi NestJS'ni ma'lumotlar bazasiga ulaymiz. 6-QISMda ORM'larni o'rgandik (TypeORM, Prisma, Mongoose); endi ularni NestJS'da — DI bilan integratsiyalashgan holda — ishlatamiz: @nestjs/typeorm, repository inject, modul sozlash. DB — har ilovaning yuragi.
Foydalanilgan rasmiy/ishonchli manbalar
- docs.nestjs.com/fundamentals — Custom providers (useClass/useValue/useFactory/useExisting), Injection scopes, Module reference (ModuleRef — get/resolve)
- docs.nestjs.com/fundamentals — Dynamic modules (forRoot/forRootAsync/register/forFeature), Asynchronous providers
- docs.nestjs.com — Providers, Dependency Injection; forwardRef (circular); Optional dependencies (@Optional)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!