NestJS

Loyiha tuzilishi: Module, Controller, Service

NestJS'da har qanday ilova uch xil qurilish blokidan yig'iladi: Module (modul), Controller (kontroller) va Service (servis). Bu uchlik NestJS falsafasining yuragi. Ularni bir marta yaxshi tushunib olsangiz, butun framework tushunarli bo'lib qoladi. Keling, har birini alohida ko'rib chiqamiz.

Mas'uliyatlarni ajratish tamoyili

NestJS arxitekturasi Separation of Concerns (mas'uliyatlarni ajratish) tamoyiliga tayanadi. Buning ma'nosi: har bir qism faqat bitta ishga javob berishi kerak. Uchlikda vazifalar shunday taqsimlanadi:

Oddiy qoida: Controller ingichka (thin) bo'lishi kerak โ€” u faqat so'rovni qabul qiladi va service'ga uzatadi. Barcha "og'ir" ish service ichida bajariladi. Bu kodni testlash va qayta ishlatishni osonlashtiradi.

@Module โ€” modul nima?

Modul โ€” bu bir-biriga bog'liq kodni birlashtiruvchi konteyner. Masalan, foydalanuvchilar bilan bog'liq barcha kod (controller, service) UsersModule ichida, mahsulotlar esa ProductsModule ichida bo'ladi. Har bir NestJS ilovada kamida bitta modul bo'ladi โ€” bu ildiz modul (AppModule).

Modul @Module dekoratori bilan belgilangan oddiy klass. Dekorator argument sifatida to'rt xossali obyekt qabul qiladi:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],            // Boshqa modullarni import qilish
  controllers: [AppController],  // Bu moduldagi controller'lar
  providers: [AppService],       // Bu moduldagi service'lar (provayderlar)
  exports: [],           // Boshqa modullar uchun ochiq provayderlar
})
export class AppModule {}

To'rt xossaning ma'nosi:

Modulni dastur bo'limi deb tasavvur qiling. Har bir bo'lim mustaqil, o'z ichida to'liq. Bu yondashuv katta ilovada har bir xususiyatni (feature) alohida modulda saqlashga imkon beradi โ€” bu feature module deb ataladi.

@Controller โ€” so'rovlarni qabul qilish

Controller HTTP so'rovlarini qabul qiladi va tegishli javobni qaytaradi. U @Controller dekoratori bilan belgilanadi. Dekoratorga berilgan satr โ€” bu marshrut prefiksi (route prefix), ya'ni ushbu controller'dagi barcha manzillarning boshi:

// src/users/users.controller.ts
import { Controller, Get } from '@nestjs/common';

@Controller('users')   // Barcha manzillar /users bilan boshlanadi
export class UsersController {

  @Get()               // GET /users
  findAll() {
    return 'Barcha foydalanuvchilar';
  }

  @Get('active')       // GET /users/active
  findActive() {
    return 'Faol foydalanuvchilar';
  }
}

Bu yerda @Get() โ€” HTTP metod dekoratori. U funksiyani ma'lum bir GET manziliga bog'laydi. Express'da biz app.get('/users', handler) yozardik; NestJS'da esa route va uni bajaradigan funksiya dekorator orqali bir-biriga ulanadi. Bu kodni ancha o'qishli qiladi.

Controller metodidan qaytgan qiymat avtomatik javobga aylanadi. Agar obyekt yoki massiv qaytarsangiz, NestJS uni avtomatik JSON'ga o'giradi. Express'dagidek res.json() chaqirish shart emas.

@Injectable โ€” service (biznes-logika)

Service โ€” bu haqiqiy ish bajariladigan joy. U @Injectable dekoratori bilan belgilangan klass. Bu dekorator NestJS'ga "bu klassni boshqa joylarga injektsiya qilish mumkin" deb aytadi (buni keyingi darsda Dependency Injection mavzusida chuqurroq ko'ramiz):

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  private users = [
    { id: 1, ism: 'Ali' },
    { id: 2, ism: 'Vali' },
  ];

  findAll() {
    return this.users;
  }

  findOne(id: number) {
    return this.users.find(u => u.id === id);
  }
}

Endi controller service'ni ishlatishi kerak. Buning uchun service controller'ning konstruktoriga qo'shiladi โ€” bu Dependency Injection deb ataladi. NestJS UsersService nusxasini avtomatik yaratadi va controller'ga uzatadi:

// src/users/users.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  // Service konstruktor orqali injektsiya qilinadi:
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll() {
    return this.usersService.findAll();  // Ishni service'ga topshiramiz
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(Number(id));
  }
}

E'tibor bering: controller hech qanday biznes-logikani o'zi bajarmaydi. U faqat so'rovni qabul qiladi va usersService'ga uzatadi. Bu ideal ajratish: controller HTTP bilan, service esa ma'lumot bilan shug'ullanadi.

Hamma narsani modulga bog'lash

Controller va service yaratganingizdan keyin ularni modulda ro'yxatdan o'tkazishingiz kerak. Aks holda NestJS ularni topolmaydi:

// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

So'ng ushbu yangi modulni ildiz modulga import qilamiz, aks holda u ilovaning bir qismi bo'lmaydi:

// src/app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule],   // UsersModule'ni ilovaga ulaymiz
})
export class AppModule {}
Eng ko'p uchraydigan boshlang'ich xato โ€” service'ni providers ro'yxatiga qo'shishni unutish. Bunda NestJS ishga tushganda "Nest can't resolve dependencies" xatosini beradi. Har doim tekshiring: service providers'da, controller controllers'da bo'lishi shart.

Nest CLI bilan avtomatik generatsiya

Bu qismlarning hammasini qo'lda yozish zerikarli. Nest CLI'ning generate (qisqasi g) buyrug'i barcha fayllarni yaratib, ularni modulga avtomatik bog'lab beradi:

# To'liq resurs yaratish (modul + controller + service + testlar):
nest generate resource users

# Yoki alohida:
nest generate module users       # nest g module users
nest generate controller users    # nest g controller users
nest generate service users       # nest g service users

nest g resource users buyrug'i ayniqsa qulay โ€” u CRUD (yaratish, o'qish, yangilash, o'chirish) uchun tayyor shablon bilan to'liq modul yaratadi. CLI hatto REST API yoki GraphQL kabi turni ham so'raydi. Bu bir necha daqiqalik qo'l ishini bir buyruqqa qisqartiradi.

CLI generatsiya qilgan fayllar avtomatik ravishda tegishli modulning controllers va providers ro'yxatiga qo'shiladi. Ya'ni yuqoridagi "modulga bog'lash" bosqichini CLI siz uchun bajaradi.

Xulosa