I am looking for a way to load my controller classes in Inversify that are annotated with @controller()
from inversify-express-utils
without needing to manage a hand crafted/manually constructed module of imports/exports.
All of the examples I am seeing seem to indicate that in your entry file you need to import each of your controllers explicitely so that inversify-express-utils
picks up on the @controller
annotations, however this feels like it would be rather tedious for applications of a medium to large size.
In plain JavaScript I would do something like recursively require each file in a directory at runtime, however I understand that due to the way TypeScript works, this isn't exactly possible?
Using the inversify-binding-decorators
package, I am able to simply annotate a service with @provide()
and that seems to be enough to have the class added to the IOC container, however that does not seem to be enough for inversify-express-utils
to discover the @controller()
annotations on the class.
Is there a way to achieve auto discovery of these @controller()
annotated classes without manually importing them into a entry file?
/services/StarwarsNamesService.ts
import { provide } from 'inversify-binding-decorators';
import * as names from 'starwars-names';
import * as matchSorter from 'match-sorter';
@provide(StarwarsNamesService)
export default class StarwarsNamesService {
public getNames(): Array<string> {
return names.all;
}
public getRandomNames(count?: number): Array<string> {
if (!count) { count = 1; }
return names.random(count);
}
public searchNames(term?: string): Array<string> {
return matchSorter(this.getNames(), term);
}
}
/controllers/StarWarsNamesController.ts
import { inject } from 'inversify';
import { controller, httpGet } from 'inversify-express-utils';
import StarwarsNamesService from '../../starwars-names/StarwarsNamesService';
@controller('/api/starwars-names')
export default class StarWarsNamesController {
@inject(StarwarsNamesService)
private starwarsNamesService: StarwarsNamesService;
@httpGet('/')
public getAll(): any {
return this.starwarsNamesService.getNames();
}
}
boostrap.ts
import 'reflect-metadata';
import * as express from "express";
import * as path from 'path';
import { InversifyExpressServer } from 'inversify-express-utils';
import { buildProviderModule } from "inversify-binding-decorators";
import { Container } from 'inversify';
// Has to be explicitly imported otherwise is undiscovered
import './controllers/StarwarsNamesController.ts';
let container = new Container();
container.load(buildProviderModule());
let server = new InversifyExpressServer(container);
let serverInstance = server.build();
serverInstance.listen(3000, () => {
console.log('Server started on port 3000 :)');
});
Thrown Error:
E:\..\..\node_modules\inversify-express-utils\lib\utils.js:10
throw new Error(constants_1.NO_CONTROLLERS_FOUND);
^
Error: No controllers have been found! Please ensure that you have register at least one Controller.
at Object.getControllersFromContainer
...