Nest.js custom Inject decorator with params - node.js

I am trying to write custom Inject decorator, so I can have access to instance of service that is being injected and pass my data there somehow. But can't reach any success. I am not sure if this is right direction and may be there are better ways to implement this idea
e.g I have Service
#Injectable()
class S3Service {
public getBucket(){
console.log(this.bucket);
}
}
class MyOtherService{
constructor(
#InjectWithParams({bucket: 'fooBucket'})
private readonly customS3Service: S3Service
){
this. customS3Service.getBucket() // may log fooBucket
}
}
class MyOtherOtherService{
constructor(
#InjectWithParams({bucket: 'barBucket'})
private readonly customS3Service: S3Service
){
this. customS3Service.getBucket() // may log barBucket
}
}
I tried few options, like (In Nest.js, how to get a service instance inside a decorator?), but I still can't access service instance in decorator

I suggest you to do this
class MyOtherOtherService{
constructor(
#InjectWithParams({bucket: 'barBucket'})
private readonly customS3Service: S3Service
){
customS3Service.getBucket() // may log barBucket
}
}
because you call it on your constructor you must remove 'this.'

Related

How to manually inject dependency in nestjs

In angular we can manually access and inject dependencies using the built in Injector class. By which you can access Injectables and Inject them without actually passing them in the constructor. Basically I want to inject a service to another service without passing it as an arg to the constructor.
This is the angular equivalent Inject a service manually
I wanted to achieve similar thing in nestjs
Note : The service to be injected also has a dependency, so I can't just instantiate it
I believe what you're looking for is Nest's ModuleRef class, where you can do something like the following:
#Injectable()
export class CatsService implements OnModuleInit {
private service: Service;
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
this.service = this.moduleRef.get(Service);
}
}
Where Service should actually be the class you are wanting to inject.
I think #Inject('token') should work as you expected
import { Injectable, Inject } from '#nestjs/common';
#Injectable()
export class HttpService<T> {
#Inject('HTTP_OPTIONS')
private readonly httpClient: T;
}
ref: https://docs.nestjs.com/providers#property-based-injection

How do you create a base service class using Nest.js + TypeORM?

I am working with Nest.js + TypeORM and hit a snag when trying to add inheritance to service classes.
I want to have a User service class that extends off of a Base service class, inheriting all the methods the it has.
This is what I've done:
export class BaseService<T> {
private repo;
constructor(repo: Repository<T>){
this.repo = repo;
}
async findAll(opts?): Promise<T[]> {
return this.repo.find(opts);
}
......
}
Then on my User service:
export class UserService extends BaseService<User> {
constructor(
#InjectRepository(User)
private userRepository: Repository<User>,
private readonly mailerService: MailerService,
) {
super(userRepository);
}
}
This works fine where I just need a single repository in the Service class but once I need more such as productRepository, as you can see it would fail due to constructor being hardcoded to accept a single repository.
I can't seem to figure out what would be the most elegant way of achieving something like this.
Does anyone know?
It is an old thread, anyways I meat this same problem and this answer may help someone else...
You can have an abstract class with common functions and boilerplate that you wich to be available in all your repositories to maintain patterns and so on...
export abstract class BaseService<T extends ObjectLiteral> {
protected repo: Repository<T>;
async findAll(opts?): Promise<T[]> {
return this.repo.find(opts);
}
......
}
Observe that constructor is omitted here and as an abstract class you should never have an instance of it, it is meant to be just an extension with common boilerplates and features that you don't want to write every single time you need a new service with the same features like a CRUD service or so...
Then you will use it like this:
export class UserService extends BaseService<User> {
constructor(
#InjectRepository(User) protected readonly repo: Repository<User>,
private readonly mailerService: MailerService,
) {
super();
}
...... extended stuff
}
I'm not sure if you need to inject repo with the same name and visibility but as it worked for me I didn't dive any further to get to know...
The bad side of this approach to me is that even if you don't have anything else to inject via constructor in your service you need to declare constructor and inject the base repository... it is a boilerplate that could be avoided too but I couldn't achieve this right now...

Inject services on demand on Guard

I have a guard that checks the ownership of a resource. If the user is the owner (created that resource), then he can access (update, read, delete).
Each resource is handled by its own service (comments is handled by the CommentsModule which has the CommentsService and so on). Each service that handles a resource with ownership implements a function called hasOwnership and the guard will call said function.
If possible, I would like my guard to inject the correct service depending on the controller that is calling it. So, if CommentsController is calling the guard, then it should inject and use CommentsService.hasOwnership.
I have tried using dynamic modules to inject the correct module/service on the imports of ACModule which hosts the guard, but that seems to be a no go as I can't properly handle the circular dependencies.
Injecting every service into the guard and selecting the correct will be very troublesome to mantain, due to the circular dependencies.
Is there a better way? This would be the desirable behavior.
#Injectable()
export default class ACGuard implements CanActivate {
constructor(
#Inject('SERVICE_KEY') private correctService
) {}
canActivate(context: ExecutionContext) {
return await correctService.hasOwnership();
}
}
Because you need a different service at run time (instead of at compile time) you are going to need to take a factory approach. It is a little troublesome to maintain as new resources are added but that's the trade-off you have to make.
First thing I would do is create a factory class to determine which service is the correct service to use based on the ExecutionContext:
export interface IService {
hasOwnership() : Promise<boolean>;
}
#Injectable()
export class ServiceFactory {
//Make sure every service returned from this method implements the "IService" interface
public getCorrectService(context: ExecutionContext) : IService {
if(context...) {
return new CommentsService();
} else if(context...) {
return new SomeOtherService();
}
}
}
Now you can inject that factory into your guard to get the correct service:
#Injectable()
export default class ACGuard implements CanActivate {
constructor(private serviceFactory: ServiceFactory) {}
canActivate(context: ExecutionContext) {
//Here's where the magic of this happens...
const correctService: Iservice = this.serviceFactory.getCorrectService(context);
return await correctService.hasOwnership();
}
}

Nest.js get injector instance

I want to create an instance of a dynamically loaded class trough Nest.js dependency injection service.
In Angular I would use Injector.create, what would be the equivalent in Nest.js ?
First of all you should get a ModuleRef which references current module, and then use its "get" method to get an instance.
#Injectable()
export class AppletService {
files: FileService;
constructor(
private moduleRef: ModuleRef,
) {
this.files = moduleRef.get(FileService);
}
}

Setting repositories and providers

Im having a little bit of a problem trying to figure out how to do the following. My apologies if thhe following seems idiotic, just new to Castle.Windsor.
Right, In my application repositories should point to diferent dbs. They all share a abstract class (Db methods abstraction) but there is no correlation between them.
So I have something like this:
public class UserService : IUserService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository) { _repository = repository; }
...
}
public class UserRepository : Mongo, IUserRepository
{
public UserRepository(DatabaseHosts.Users UsersHost) : base(UsersHost) { }
...
}
All configuration settings are strongly typed and so far I am calling a Installer for the Settings Service before i call Install on the rest.
My question would be: Do i have to register services and Respositories or there is something im missing?
I think, We could allow access to the DbHost property from the Service, but i rather like not.
We also have providers to external systems which might need some sort of initialization.
So far i have soemthing like this:
public class ServicesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IUserService>()
.ImplementedBy<IUserService>()
.LifeStyle.Singleton);
}
}
Ta
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IUserService>()
.ImplementedBy<UserService>()
.LifeStyle.Singleton);
}
you have to register the concrete service "UserService" to the interface in order to allow the container to determine which concrete to resolve.

Resources