2

I have scinario I implemented before in express app using inversifyjs, I need to implement it using nestjs.

I have services(A, B,C) that implement abstact class(Service Abstract) which inheret from the interface (IService). I need to inject one from above services (A or B or C) based on param in route (/:serviceType). How can I achieve that in nest ?

Ashraf Atef
  • 169
  • 1
  • 1
  • 8
  • Probably a ‘factory’ provider that will return one of those services based on an arg (route param). – Estus Flask Oct 25 '20 at 23:36
  • Do you mean using custom provider `useFactory`? or you mean I create a factory service that return instance of service based on param value. I can't find enough examples to apply `useFactory`. In inversify I can do it using factory in inversify config file. – Ashraf Atef Oct 26 '20 at 04:22
  • These two options don't contradict each other. The way it would work depends on whether you need A, etc to be singletons or not. – Estus Flask Oct 26 '20 at 09:38

1 Answers1

2

It can be function service defined with useFactory that returns A, B or else based on provided argument:

providers: [{
  provide: 'GET_AB',
  useFactory: (a: A, b: B) => {
    return (name) => {
     if (name === 'a')
       return a;
     else if (name === 'b')
       return b;
    };
  },
  inject: [A, B]
}]

Injected GET_AB is a function that is used like aOrB = getAB('a');

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thanks @estus-flask for your response. Where to put this code in `app.module.ts` right or put it in seperate file and import it in `app.module.ts`? and how can I inject it in service callead for example `product.service.ts` ? Thanks for your help – Ashraf Atef Oct 26 '20 at 10:29
  • It's up to you but I don't see a reason to define it in separate file, it's not a reusable code, just put it inside `@Module(...)`. It's injected with `@Inject` this way https://docs.nestjs.com/providers#property-based-injection or this way https://docs.nestjs.com/fundamentals/custom-providers#non-class-based-provider-tokens , as long as product.service belongs to a module that has this provider. – Estus Flask Oct 26 '20 at 10:34
  • so the injection will be like that : `@Inject('GET_AB') providerFactory : GetAB` , but `GetAB` it is undefined – Ashraf Atef Oct 26 '20 at 10:48
  • and to call it `this.providerFactory('a')` , right ? – Ashraf Atef Oct 26 '20 at 10:49
  • Yes, it's called like that. There's no GetAB and it's unnecessary to have it because dep type isn't used for DI with `@Inject`. You may want to declare factory function outside `providers` just for typing purposes, `export const getABFactory = (a: A, b: B) => ...`, and then it'll be `@Inject('GET_AB') providerFactory : ReturnType` – Estus Flask Oct 26 '20 at 11:40
  • here is my constructor now `constructor(@Inject('GET_AB') providerFactory){ this.factoryProvider = providerFactory }` and I called it within a method `const providerService :ChannelsAbstract= this.factoryProvider('tyntec')` when I call function called findX from channelsAbstract like this `providerService.findX()` I got error that findX is not a function – Ashraf Atef Oct 26 '20 at 12:33
  • This depends on your implementation details. Debug what providerService is in your case. Also it won't work if `A`, etc aren't class providers in current injector. – Estus Flask Oct 26 '20 at 16:34