thiagobustamante / typescript-rest

This is a lightweight annotation-based expressjs extension for typescript.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to Use Inversify?

ccravens opened this issue · comments

I see references to creating our own ServiceFactory for using other IoC containers like Inversify. I've been working with this for several hours now and can not figure out how it is supposed to work with Inversify. I am successfully binding a service with Inversify that I can use outside of a typescript-rest controller, and I've implemented the following custom class:

import {
  ServiceContext,
  ServiceFactory,
} from 'typescript-rest/src/server/model/server-types';

export class InversifyServiceFactory implements ServiceFactory {
  public create(serviceClass: any, context: ServiceContext) {
    console.log('>>> CREATE SERVICE FACTORY >>>');
    return new serviceClass();
    // return Container.get(serviceClass);
  }

  public getTargetClass(serviceClass: () => {}) {
    console.log('>>> CREATE SERVICE FACTORY >>>');
    if (Array.isArray(serviceClass)) {
      return null;
    }
    let typeConstructor: any = serviceClass;
    if (typeConstructor.name && typeConstructor.name !== 'ioc_wrapper') {
      return typeConstructor as FunctionConstructor;
    }
    typeConstructor = typeConstructor.__parent;
    while (typeConstructor) {
      if (typeConstructor.name && typeConstructor.name !== 'ioc_wrapper') {
        console.log('>>> RETURN 2');
        return typeConstructor as FunctionConstructor;
      }
      typeConstructor = typeConstructor.__parent;
    }
    console.log(
      'Can not identify the base Type for requested target: %o',
      serviceClass
    );
    throw new TypeError('Can not identify the base Type for requested target');
  }
}

And I correctly inject it with:

    Server.registerServiceFactory(new InversifyServiceFactory());

I see that the typescript-rest-ioc does the following:

return Container.get(serviceClass);

However, for Inversify, this is what we're provided:

    get<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>): T;
    getTagged<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>, key: string | number | symbol, value: any): T;
    getNamed<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>, named: string | number | symbol): T;
    getAll<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>): T[];
    getAllTagged<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>, key: string | number | symbol, value: any): T[];
    getAllNamed<T>(serviceIdentifier: interfaces.ServiceIdentifier<T>, named: string | number | symbol): T[];

Which takes an interfaces.ServiceIdentifier.

I'm sure I'm missing something simple, but hoping I can get some quick guidance about how to complete my ServiceFactory since I've seen several places claiming that Inversify is usable, but I keep getting undefined when I inject into the controller.

Thanks!

Ok I figure I can pass the Inversify container to my custom ServiceFactory. What I've noticed is that for the following handler:

  public create(serviceClass: any, context: ServiceContext) {
    console.log('>>> CREATE SERVICE FACTORY >>>');
    return return this.container.get(serviceClass);
  }

serviceClass is a handle to the Controller class, not to the injected service. For example, if I'm inject a service into MyController called MyService, the create() method is getting MyController. So when I try and use the Inversify container to get the serviceClass, it obviously doesn't know anything about the controller and I'm given this error:

Error: No matching bindings found for serviceIdentifier: MyController

How do I get the handle for the MyService property so I can get the property rather than the controller? I really wish that there was some sort of example in the documentation or test code or something. Thank you!

Ok I figure I can pass the Inversify container to my custom ServiceFactory. What I've noticed is that for the following handler:

  public create(serviceClass: any, context: ServiceContext) {
    console.log('>>> CREATE SERVICE FACTORY >>>');
    return return this.container.get(serviceClass);
  }

serviceClass is a handle to the Controller class, not to the injected service. For example, if I'm inject a service into MyController called MyService, the create() method is getting MyController. So when I try and use the Inversify container to get the serviceClass, it obviously doesn't know anything about the controller and I'm given this error:

Error: No matching bindings found for serviceIdentifier: MyController

How do I get the handle for the MyService property so I can get the property rather than the controller? I really wish that there was some sort of example in the documentation or test code or something. Thank you!

Hi - Were you able to get it working?