Пошук уроків, статей та іншого контенту
Створите модуль, розберете його структуру та зрозумієте роль декоратора @Module().
Модуль — це клас, який описує частину структури застосунку. Він об’єднує пов’язані між собою:
контролери;
сервіси та інші провайдери;
імпортовані модулі;
провайдери, доступні для інших модулів.
У NestJS модулі допомагають розділити великий застосунок на логічні частини. Наприклад:
UsersModule — робота з користувачами;
ProductsModule — робота з товарами;
AuthModule — автентифікація;
OrdersModule — замовлення.
Кожен модуль зазвичай відповідає за одну функціональну область.
@Module()Модуль створюється за допомогою декоратора @Module():
import { Module } from '@nestjs/common';
@Module({})
export class UsersModule {}@Module() приймає об’єкт із метаданими. У цих метаданих ми описуємо склад модуля.
Основні властивості:
controllers — контролери модуля;
providers — провайдери модуля, наприклад сервіси;
imports — інші модулі, які потрібні цьому модулю;
exports — провайдери, які модуль дозволяє використовувати іншим модулям.
Розглянемо простий модуль для роботи з користувачами.
Сервіс містить бізнес-логіку:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findAll(): string[] {
return ['Олена', 'Андрій', 'Марія'];
}
}Декоратор @Injectable() повідомляє NestJS, що клас можна використовувати як провайдер і створювати через систему залежностей.
Контролер обробляє HTTP-запити:
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): string[] {
return this.usersService.findAll();
}
}Контролер використовує UsersService через конструктор.
Тепер об’єднаємо контролер і сервіс у модулі:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Модуль повідомляє NestJS:
UsersController належить цьому модулю;
UsersService є провайдером цього модуля;
контролер може отримати UsersService через залежність у конструкторі.
Головним модулем застосунку зазвичай є AppModule. Інші функціональні модулі підключаються до нього через властивість imports.
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
})
export class AppModule {}Після цього UsersModule стає частиною застосунку, а маршрут GET /users буде доступний у запущеному NestJS-застосунку.
Структура файлів:
src/
├── app.module.ts
├── main.ts
└── users/
├── users.controller.ts
├── users.module.ts
└── users.service.tssrc/users/users.service.tsimport { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findAll(): string[] {
return ['Олена', 'Андрій', 'Марія'];
}
}src/users/users.controller.tsimport { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): string[] {
return this.usersService.findAll();
}
}src/users/users.module.tsimport { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}src/app.module.tsimport { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
})
export class AppModule {}src/main.tsimport { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();Після запуску застосунку запит:
GET http://localhost:3000/usersповерне:
["Олена", "Андрій", "Марія"]providersУ providers вказують сервіси та інші провайдери, які використовуються всередині модуля:
@Module({
providers: [UsersService],
})
export class UsersModule {}Якщо сервіс використовується в конструкторі контролера, він має бути зареєстрований у providers цього модуля або доступний через імпортований модуль.
Наприклад, такий контролер потребує UsersService:
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
}Тому UsersService має бути доданий до модуля:
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}controllersУ controllers вказують контролери, маршрути яких належать модулю:
@Module({
controllers: [UsersController],
})
export class UsersModule {}Якщо контролер не додати до controllers, NestJS не зареєструє його маршрути.
Зазвичай контролери модуля працюють із провайдерами цього ж модуля:
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}importsВластивість imports використовується, коли один модуль потребує функціональності іншого модуля.
Наприклад, OrdersModule може використовувати UsersService з UsersModule.
Спочатку потрібно експортувати сервіс із UsersModule:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}Потім імпортувати UsersModule у OrdersModule:
import { Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';
@Module({
imports: [UsersModule],
})
export class OrdersModule {}Тепер провайдер, експортований із UsersModule, може бути використаний у OrdersModule.
exportsЗа замовчуванням провайдер доступний лише всередині модуля, у якому його зареєстровано.
Щоб дозволити іншим модулям використовувати провайдер, його потрібно додати до exports:
@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}exports формує публічну частину модуля. Інші модулі не отримують автоматичний доступ до всіх його провайдерів.
Для використання експортованого провайдера інший модуль має:
імпортувати модуль, який його експортує;
додати цей модуль до imports.
Приклад модуля замовлень, який використовує сервіс користувачів:
import { Controller, Get } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';
import { UsersService } from '../users/users.service';
@Controller('orders')
export class OrdersController {
constructor(private readonly usersService: UsersService) {}
@Get()
getUserNames(): string[] {
return this.usersService.findAll();
}
}
@Module({
imports: [UsersModule],
controllers: [OrdersController],
})
export class OrdersModule {}У цьому прикладі:
UsersModule експортує UsersService;
OrdersModule імпортує UsersModule;
OrdersController отримує UsersService через конструктор.
Nest CLI може створити модуль автоматично:
nest generate module usersАбо скорочений варіант:
nest g module usersКоманда створить файл модуля та додасть його до структури проєкту. Контролер і сервіс можна створити окремими командами:
nest g controller users
nest g service usersПісля цього їх потрібно зареєструвати в UsersModule. У сучасних версіях Nest CLI це зазвичай робиться автоматично, але структуру модуля все одно важливо розуміти.
Для нової функціональної області можна діяти так:
Створити папку, наприклад users.
Створити сервіс users.service.ts.
Створити контролер users.controller.ts.
Створити модуль users.module.ts.
Додати контролер до controllers.
Додати сервіс до providers.
Підключити модуль до AppModule через imports.
Додати потрібні провайдери до exports, якщо їх використовуватимуть інші модулі.
providers@Module({
controllers: [UsersController],
})
export class UsersModule {}Якщо UsersController залежить від UsersService, але сервіс не зареєстрований, NestJS не зможе створити контролер.
Правильно:
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}importsМожна правильно створити UsersModule, але забути підключити його до AppModule:
@Module({})
export class AppModule {}У такому випадку NestJS не завантажить UsersModule.
Правильно:
@Module({
imports: [UsersModule],
})
export class AppModule {}exportsЯкщо інший модуль має використовувати UsersService, недостатньо лише додати його до providers:
@Module({
providers: [UsersService],
})
export class UsersModule {}Потрібно також експортувати сервіс:
@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}controllersЯкщо контролер не вказано в модулі, його маршрути не будуть зареєстровані:
@Module({
providers: [UsersService],
})
export class UsersModule {}Правильно:
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Модуль у NestJS об’єднує пов’язані контролери та провайдери.
Модуль створюється за допомогою декоратора @Module().
controllers містить контролери модуля.
providers містить сервіси та інші провайдери.
imports підключає інші модулі.
exports відкриває провайдери для модулів, які імпортують поточний модуль.
Кореневий AppModule підключає функціональні модулі застосунку.
Модульна структура робить застосунок організованим і спрощує повторне використання функціональності.