Skip to content

Commit 81c4da9

Browse files
author
hirsch88
committed
refactor ioc
1 parent 1e8698e commit 81c4da9

File tree

4 files changed

+162
-36
lines changed

4 files changed

+162
-36
lines changed

src/api/middlewares/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import * as request from 'request';
9-
import container from '../../container';
9+
import { ioc } from '../../core/IoC';
1010
import { Log } from '../../core/log';
1111
import { Types } from '../../constants/Types';
1212
import { Service } from '../../constants/Targets';
@@ -19,4 +19,4 @@ const logPrefix = 'api:middleware';
1919

2020

2121
export const authenticate = Authenticate(request, new Log(`${logPrefix}:authenticate`));
22-
export const populateUser = PopulateUser(() => container.getNamed<UserService>(Types.Service, Service.UserService), new Log(`${logPrefix}:populateUser`));
22+
export const populateUser = PopulateUser(() => ioc.Container.getNamed<UserService>(Types.Service, Service.UserService), new Log(`${logPrefix}:populateUser`));

src/container.ts

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { Core, Model, Controller, Service, Repository } from './constants/Target
1616
*/
1717
import { events, EventEmitter } from './core/api/events';
1818
import { Log } from './core/log';
19+
import { ioc } from './core/IoC';
1920

2021
/**
2122
* User Resource
@@ -25,31 +26,34 @@ import { UserService } from './api/services/UsersService';
2526
import { UserRepository } from './api/repositories/UserRepository';
2627
import { User } from './api/models/User';
2728

28-
29-
const container = new Container();
30-
31-
container.bind<EventEmitter>(Types.Core).toConstantValue(events).whenTargetNamed(Core.Events);
32-
container.bind<typeof Log>(Types.Core).toConstantValue(Log).whenTargetNamed(Core.Log);
33-
34-
/**
35-
* Model
36-
*/
37-
container.bind<any>(Types.Model).toConstantValue(User).whenTargetNamed(Model.User);
38-
39-
/**
40-
* Controllers
41-
*/
42-
container.bind<interfaces.Controller>(Types.Controller).to(UserController).whenTargetNamed(Controller.UserController);
43-
44-
/**
45-
* Services
46-
*/
47-
container.bind<UserService>(Types.Service).to(UserService).whenTargetNamed(Service.UserService);
48-
49-
/**
50-
* Repositories
51-
*/
52-
container.bind<UserRepository>(Types.Repository).to(UserRepository).whenTargetNamed(Repository.UserRepository);
53-
54-
55-
export default container;
29+
ioc.configure((container: Container) => {
30+
console.log('--> CONTAINER should be last');
31+
32+
/**
33+
* Core
34+
*/
35+
container.bind<EventEmitter>(Types.Core).toConstantValue(events).whenTargetNamed(Core.Events);
36+
container.bind<typeof Log>(Types.Core).toConstantValue(Log).whenTargetNamed(Core.Log);
37+
38+
/**
39+
* Model
40+
*/
41+
container.bind<any>(Types.Model).toConstantValue(User).whenTargetNamed(Model.User);
42+
43+
/**
44+
* Controllers
45+
*/
46+
container.bind<interfaces.Controller>(Types.Controller).to(UserController).whenTargetNamed(Controller.UserController);
47+
48+
/**
49+
* Services
50+
*/
51+
container.bind<UserService>(Types.Service).to(UserService).whenTargetNamed(Service.UserService);
52+
53+
/**
54+
* Repositories
55+
*/
56+
container.bind<UserRepository>(Types.Repository).to(UserRepository).whenTargetNamed(Repository.UserRepository);
57+
58+
return container;
59+
});

src/core/Bootstrap.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import { my } from 'my-express';
2020
import { exceptionHandler, extendExpressResponse } from './api';
2121
import { events } from './api/events';
2222
import { Server } from './Server';
23+
import { ioc } from './IoC';
2324
import { Log } from './log';
24-
import container from '../container';
25+
import '../container';
2526

2627
const log = new Log('core:Bootstrap');
2728

@@ -50,11 +51,12 @@ export class Bootstrap {
5051
this.defineExpressApp();
5152
}
5253

53-
public main(): void {
54+
public async main(): Promise<void> {
5455
log.info('Configuring app...');
5556
this.app = this.appConfiguration(this.app);
5657

57-
this.bindIoC();
58+
await this.bindIoC();
59+
this.setupIoC();
5860
this.startServer();
5961
}
6062

@@ -68,9 +70,14 @@ export class Bootstrap {
6870
this.app.set('port', Bootstrap.normalizePort(Environment.get<string>('PORT') || Environment.get<string>('APP_PORT')));
6971
}
7072

71-
private bindIoC(): void {
72-
log.info('Binding IoC...');
73-
this.inversifyExpressServer = new InversifyExpressServer(container, undefined, {
73+
private async bindIoC(): Promise<void> {
74+
log.info('Binding IoC modules...');
75+
await ioc.bindModules();
76+
}
77+
78+
private setupIoC(): void {
79+
log.info('Setting up IoC...');
80+
this.inversifyExpressServer = new InversifyExpressServer(ioc.Container, undefined, {
7481
rootPath: Environment.get<string>('APP_URL_PREFIX')
7582
}, this.app);
7683
this.inversifyExpressServer.setConfig((a) => a.use(extendExpressResponse));

src/core/IoC.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* IOC - CONTAINER
3+
* ----------------------------------------
4+
*
5+
* Bind every controller and service to the ioc container. All controllers
6+
* will then be bonded to the express structure with their defined routes.
7+
*/
8+
9+
import * as fs from 'fs';
10+
import { interfaces } from 'inversify-express-utils';
11+
import { Container } from 'inversify';
12+
import { Types } from '../constants/Types';
13+
import { Core, Controller, Model, Service, Repository } from '../constants/Targets';
14+
15+
import { events, EventEmitter } from './api/events';
16+
import { Log } from './log';
17+
18+
19+
class IoC {
20+
21+
public container: Container;
22+
public customConfiguration: (container: Container) => Container;
23+
24+
constructor() {
25+
this.container = new Container();
26+
}
27+
28+
public get Container(): Container {
29+
return this.container;
30+
}
31+
32+
public configure(configuration: (container: Container) => Container): void {
33+
this.customConfiguration = configuration;
34+
}
35+
36+
public async bindModules(): Promise<void> {
37+
// this.bindCore();
38+
// this.bindModels();
39+
// this.bindControllers();
40+
41+
this.container = this.customConfiguration(this.container);
42+
}
43+
44+
private bindCore(): void {
45+
this.container.bind<typeof Log>(Types.Core).toConstantValue(Log).whenTargetNamed(Core.Log);
46+
}
47+
48+
private async bindControllers(): Promise<void> {
49+
this.getFiles('/controllers', (files: string[]) => {
50+
files.forEach((file: any) => {
51+
console.log(file);
52+
const fileExport = require(`${file.path}/${file.fileName}`);
53+
console.log(fileExport);
54+
this.container
55+
.bind<interfaces.Controller>(Types.Controller)
56+
.to(fileExport[file.name])
57+
.whenTargetNamed(Controller[file.name]);
58+
});
59+
});
60+
}
61+
62+
private bindModels(): void {
63+
console.log('Models');
64+
this.getFiles('/models', (files: string[]) => {
65+
files.forEach((file: any) => {
66+
const fileExport = require(`${file.path}/${file.fileName}`);
67+
this.validateExport(fileExport[file.name]);
68+
this.validateTarget(Model, file.name);
69+
console.log(Model[file.name]);
70+
this.container
71+
.bind<any>(Types.Model)
72+
.to(fileExport[file.name])
73+
.whenTargetNamed(Model[file.name]);
74+
});
75+
});
76+
}
77+
78+
private getBasePath(): string {
79+
const baseFolder = __dirname.indexOf('/src/') >= 0 ? '/src/' : '/dist/';
80+
const baseRoot = __dirname.substring(0, __dirname.indexOf(baseFolder));
81+
return `${baseRoot}${baseFolder}api`;
82+
}
83+
84+
private getFiles(path: string, done: (files: any[]) => void): void {
85+
fs.readdir(this.getBasePath() + path, (err: any, files: string[]): void => {
86+
if (err) {
87+
console.error(err);
88+
}
89+
done(files.map((fileName: string) => ({
90+
path: this.getBasePath() + path,
91+
fileName: fileName,
92+
name: this.parseName(fileName)
93+
})));
94+
});
95+
}
96+
97+
private parseName(fileName: string): string {
98+
return fileName.substring(0, fileName.length - 3);
99+
}
100+
101+
private validateExport(value: any): void {
102+
if (!value) {
103+
throw new Error(`${value} is not defined in the target constants`);
104+
}
105+
}
106+
107+
private validateTarget(target: any, value: any): void {
108+
if (target && target[value] === undefined) {
109+
throw new Error(`${value} is not defined in the target constants`);
110+
}
111+
}
112+
113+
}
114+
115+
export const ioc = new IoC();

0 commit comments

Comments
 (0)