tsedio / tsed

:triangular_ruler: Ts.ED is a Node.js and TypeScript framework on top of Express to write your application with TypeScript (or ES6). It provides a lot of decorators and guideline to make your code more readable and less error-prone. ⭐️ Star to support our work!
https://tsed.io/
MIT License
2.83k stars 286 forks source link

Integration with InversifyJS #581

Closed DimiTech closed 5 years ago

DimiTech commented 5 years ago

Information

Description

I want to integrate Ts.ED (ts-express-decorators) with an existing project that uses InversifyJS.

I know that you don't plan to integrate any other DI system any time soon, what I only need is the @ServerSettings({ mount: ____ }) mount property to accept instances of Controllers as well as their Constructors (as it is now). That way I could get the Controllers from InversifyJS and put them in Ts.ED.

If there is a better way to integrate with InversifyJS I'm open for suggestions!

You can also take a look how I integrated Overnight with InversifyJS here: https://github.com/DusanDimitric/node-typescript-boilerplate/blob/19b41e0dd592b66c3805bd5c4778685303faf29a/src/web/server/ExpressServer.ts#L43

Example

import {} from "@tsed/common";
@ServerSettings({
  rootDir,
  mount: {
    '/rest': [
+      container.get<Controller>(TYPES.HomeController),
    ],
  },
  acceptMimes : ['application/json'],
})

Acceptance criteria

Thanks for all the hard work!

Romakita commented 5 years ago

Hello @DusanDimitric, Is not possible, because declaring Controller require to use @Controller decorator which will add your controller to the DI registry and add endpoint path configuration. mount option is just here define the main endpoint for your controllers.

One possibility is to register your controller with registerController and create your custom decorator as following:

export function Controller(options: PathParamsType | IControllerProvider, ...children: Type<any>[]): Function {
  return (target: any): void => {
    const useFactory = () => {
       return container.get<any>(target)
    }

    if (typeof options === "string" || options instanceof RegExp || isArrayOrArrayClass(options)) {
      registerController({
        provide: target,
        path: options,
        deps: [],
        children
      });
    } else {
      registerController({
        provide: target,
        children: (options as IControllerProvider).dependencies || (options as IControllerProvider).children,
        ...options,
        deps: [],
        useFactory
      });
    }
  };
}

Then use it on your class:

@InversifyController('/')
class MyCtrl {

}
@ServerSettings({
  rootDir,
  mount: {
    '/rest': [
+      MyCtrl,
    ],
  },
  acceptMimes : ['application/json'],
})

You can try this example :)

DimiTech commented 5 years ago

Thanks @Romakita. I did indeed make this to work but Inversify DI injection does not work with my controllers now.

Anyways, thanks a lot!