Vitalii Del Vorobioff
Vitalii Del Vorobioff

Reputation: 524

How to inject service into imported service Nestjs

I have custom module AuthModule with AuthService, AuthController with routes and so on, that work fine, and want to share this module between several projects as a package. The questions is how to extend imported AuthService from this package and how to inject in it additional services?

More details

Into my custom AuthService, that I want to place in package, is injected class UserService, that by default gets from the database some User data and return it to client side . I need to inject into AuthService another, for example ProfileService from application, that get from database User extra data. The aim is to merge User main data and User extra data, and return this bunch to client

Upvotes: 12

Views: 17723

Answers (3)

Gil Cohen
Gil Cohen

Reputation: 351

I'm using GraphQL and my resolver is decorated with @Resolver(), so I had to not use @Dependencies (since I got a TypeError, that my functions are not functions).

I exported my service:

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserResolver } from './user.resolver';

@Module({
  providers: [UserResolver, UserService],
  exports: [UserService], //This line is new
})
export class UserModule {}

Then, I imported it in the other module:

import { Module } from '@nestjs/common';
import { IngredientService } from './ingredient.service';
import { IngredientResolver } from './ingredient.resolver';
import { UserModule } from 'src/user/user.module';  //This line is new

@Module({
  providers: [IngredientResolver, IngredientService],
  imports: [UserModule], //This line is new
})
export class IngredientModule {}

Then, in my resolver, I added it in the constructor:

import { UserService } from 'src/user/user.service'; //This line is new

@Resolver(() => Ingredient)
export class IngredientResolver {
  constructor(
    private readonly ingredientService: IngredientService,
    private readonly userService: UserService, //This line is new
  ) {}

Upvotes: 0

Jesús Franco
Jesús Franco

Reputation: 316

I don't see really the need for a Dynamic Module here.

Indeed, only is needed that the service you want to inject into other entity managed by NestJs, is exported from your AuthModule, and AuthModule imported in the Module you want other entities have injected your AuthService.

import { Module } from '@nestjs/common'
import { AuthService } from './AuthService'

@Module({
  providers: [
    AuthService,
    // ... others
  ],
  exports: [
    AuthService
  ]
})
export class CommonModule {}

Then in your dependent class (let's say another Controller, but could be anything like a GraphQL Resolver, Interceptor, or whatever), you declare the dependency on AuthService.

import { AuthService } from '../auth/AuthService'
import { Dependencies } from '@nestjs/common'

@Dependencies(AuthService)
export class DependentController {
  constructor (authService) {
    this.authService = authService
  }
}

Finally, in order to the AuthService be available to the dependent controller, it has to be imported in the same Module that controller is provided.

import { Module } from '@nestjs/common'
import { CommonModule } from '../auth/CommonModule'
import { DependentController } from './controller/DependentController'

@Module({
  imports: [
    CommonModule,
    // ...others
  ],
  providers: [
    DependentController,
    // ...others
  ]
})
export class ControllerModule {}

I understand that the syntax could be shorter and without using Dependencies decorator in typescript, however the core of the matter is exporting the shared Service from the Module it is provided, then importing that module into the Module other classes that require it.

Upvotes: 7

VinceOPS
VinceOPS

Reputation: 2720

This is one of the use cases Dynamic Modules have been created for.

import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';

@Module({
  providers: [Connection],
})
export class DatabaseModule {
  static forRoot(entities = [], options?): DynamicModule {
    const providers = createDatabaseProviders(options, entities);
    return {
      module: DatabaseModule,
      providers: providers,
      exports: providers,
    };
  }
}

In this example, see how providers are given (dynamically) to the result module.

Your package should follow the same pattern: expose a static method which allows building a DynamicModule, so you can resolve your other services (internal or external) as you want (building your own array of providers).

Upvotes: 3

Related Questions