Інтеграція сервісу з іншого модуля в Nest.js передбачає кілька етапів, які гарантують правильне впровадження залежностей та організовану структуру модулів. Розглянемо процес експорту та імпорту сервісів на прикладі двох окремих модулів.
Створення проєкту Nest.js
Для початку роботи з Nest.js необхідно мати встановлений CLI на вашому пристрої. Якщо його немає, скористайтеся наступною командою для інсталяції:
npm install -g @nestjs/cli
Після успішної інсталяції Nest.js CLI, запустіть наступну команду для генерації нового проєкту:
nest new <назва-проєкту>
Замініть “<назва-проєкту>” на бажану назву вашого проєкту. Ця команда створить новий проєкт Nest.js з вказаним ім’ям.
Наразі структура вашого проєкту має бути схожою на зображення нижче:
Для практики інтеграції сервісу з одного модуля до іншого, ми створимо два модулі: module-a та module-b. Для кожного з них також згенеруємо відповідні файли сервісу та контролера.
Запустіть цю команду для генерації модуля a:
nest generate module module-a
І аналогічну команду для module-b:
nest generate module module-b
Далі, створіть файли сервісу та контролера для module-a за допомогою цієї команди:
nest generate service module-a && nest generate controller module-a
І виконайте аналогічну команду для module-b:
nest generate service module-b && nest generate controller module-b
Тепер структура вашого проєкту повинна включати каталоги src/module-a та src/module-b, як показано на зображенні:
Експорт сервісу з модуля A
Для експорту сервісу з модуля `module-a`, потрібно оголосити його як експорт у файлі модуля `module-a` (`module-a.module.ts`). За замовчуванням, Nest.js CLI не додає масив експорту у декоратор `@Module`, тому створений файл модуля буде виглядати наступним чином:
import { Module } from '@nestjs/common'; import { ModuleAService } from './module-a.service'; import { ModuleAController } from './module-a.controller'; @Module({ providers: [ModuleAService], controllers: [ModuleAController], }) export class ModuleAModule {}
Щоб зробити сервіс `service-a` (`module-a.service.ts`) доступним для модулів, що імпортують `module-a`, створіть масив `exports` у декораторі `@Module` та додайте до нього `ModuleAService`.
Ось приклад:
import { Module } from '@nestjs/common'; import { ModuleAService } from './module-a.service'; import { ModuleAController } from './module-a.controller'; @Module({ providers: [ModuleAService], controllers: [ModuleAController], exports: [ModuleAService], }) export class ModuleAModule {}
Для тестування, додайте просту функцію до файлу сервісу `module-a` (`module-a.service.ts`):
import { Injectable } from '@nestjs/common'; @Injectable() export class ModuleAService { getHello(): string { return 'Hello from Module A!'; } }
Ця функція повертає звичайний текстовий рядок. Для перевірки правильності імпорту цього сервісу, ми викличемо цю функцію з `module-b` після впровадження `service-a`.
Імпорт сервісу в модуль B
Для імпорту одного модуля в інший, необхідно вказати його у масиві `imports` модуля-отримувача. У цьому випадку, потрібно додати `module-a` до масиву `imports` декоратора `@Module` в `module-b`.
Як і раніше, Nest.js CLI не створює масив `imports` автоматично, тому його потрібно додати вручну.
Спочатку імпортуйте батьківський модуль (`module-a.module.ts`) у модуль-отримувач (`module-b.module.ts`), створіть масив `imports` та додайте `ModuleAModule` до нього:
import { Module } from '@nestjs/common'; import { ModuleBController } from './module-b.controller'; import { ModuleBService } from './module-b.service'; import { ModuleAModule } from '../module-a/module-a.module'; @Module({ imports: [ModuleAModule], controllers: [ModuleBController], providers: [ModuleBService], }) export class ModuleBModule {}
Далі, відкрийте файл `module-b.service.ts` та імпортуйте декоратор `Inject` і `ModuleAServerice` з `@nestjs/common` та `../module-a/module-a.service` відповідно:
import { Injectable, Inject } from '@nestjs/common'; import { ModuleAService } from '../module-a/module-a.service';
Декоратор `Inject` позначає свій параметр як ціль для впровадження залежностей.
Далі, додайте наступний код до класу `ModuleBService`:
@Inject(ModuleAService) private readonly moduleAService: ModuleAService;
Цей блок коду надає вашому `ModuleBService` доступ до методів, доступних у вашому `ModuleAService`.
Тепер ви можете протестувати сервіс, викликавши метод `getHello` модуля `ModuleAService`.
import { Injectable, Inject } from '@nestjs/common'; import { ModuleAService } from 'src/module-a/module-a.service'; @Injectable() export class ModuleBService { @Inject(ModuleAService) private readonly moduleAService: ModuleAService; getHello(): string { return this.moduleAService.getHello(); } }
Далі, відкрийте файл `module-b.controller.ts` та замініть згенерований код наступним:
import { Controller, Get } from '@nestjs/common'; import { ModuleBService } from './module-b.service'; @Controller('module-b') export class ModuleBController { constructor(private readonly moduleBService: ModuleBService) {} @Get('/hello') getHello(): string { return this.moduleBService.getHello(); } }
Наведений вище блок коду встановлює обробник маршруту GET для функції `getHello`.
Нарешті, виконайте GET-запит за допомогою `curl` до `localhost:3000/module-b/hello`. Команда має вивести “Hello from Module A!” до вашої консолі.
Ви успішно впровадили сервіс в інший модуль. Це може стати корисним, коли ви розробляєте API за допомогою Nest.js, де кілька модулів повинні викликати методи один одного.
Переваги міжмодульного впровадження
Хоча прямий виклик сервісу з іншого модуля може здаватися спочатку простішим, у довгостроковій перспективі це може призвести до більш складної, менш зручної для обслуговування та менш масштабованої системи.
З іншого боку, міжмодульне впровадження сприяє модульності коду та повторному використанню, що полегшує його обслуговування. Крім того, воно централізує залежності, покращує тестування та підтримує масштабовану, декомпоновану архітектуру.