Skip to content

Commit 763ec24

Browse files
committed
Merge branch 'master' of https://github.com/gritcode/routing-controllers into gritcode-master
2 parents 71f3f8e + 2b0b207 commit 763ec24

File tree

9 files changed

+98
-29
lines changed

9 files changed

+98
-29
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,39 @@ export class UsersController {
13981398
}
13991399
```
14001400
1401+
For other IoC providers that don't expose a `get(xxx)` function, you can create an IoC adapter using `IocAdapter` like so:
1402+
1403+
```typescript
1404+
// inversify-adapter.ts
1405+
import { IoCAdapter } from 'routing-controllers'
1406+
import { Container } from 'inversify'
1407+
1408+
class InversifyAdapter implements IocAdapter {
1409+
constructor (
1410+
private readonly container: Container
1411+
) {
1412+
}
1413+
1414+
get<T> (someClass: ClassConstructor<T>, action?: Action): T {
1415+
const childContainer = this.container.createChild()
1416+
childContainer.bind(API_SYMBOLS.ClientIp).toConstantValue(action.context.ip)
1417+
return childContainer.resolve<T>(someClass)
1418+
}
1419+
}
1420+
```
1421+
1422+
And then tell Routing Controllers to use it:
1423+
```typescript
1424+
// Somewhere in your app startup
1425+
import { useContainer } from 'routing-controllers'
1426+
import { Container } from 'inversify'
1427+
import { InversifyAdapter } from './inversify-adapter.ts'
1428+
1429+
const container = new Container()
1430+
const inversifyAdapter = new InversifyAdapter(container)
1431+
useContainer(inversifyAdapter)
1432+
```
1433+
14011434
## Custom parameter decorators
14021435
14031436
You can create your own parameter decorators.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "routing-controllers",
3-
"private": true,
2+
"name": "@gritcode/routing-controllers",
3+
"private": false,
44
"version": "0.8.0",
55
"description": "Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage for Express / Koa using TypeScript.",
66
"license": "MIT",
@@ -38,6 +38,10 @@
3838
"reflect-metadata": "^0.1.13",
3939
"template-url": "^1.0.0"
4040
},
41+
"peerDependencies": {
42+
"class-transformer": "^0.2.3",
43+
"class-validator": "0.10.1"
44+
},
4145
"devDependencies": {
4246
"@types/chai": "^4.2.3",
4347
"@types/chai-as-promised": "7.1.2",
@@ -82,10 +86,6 @@
8286
"typedi": "~0.8.0",
8387
"typescript": "~3.6.3"
8488
},
85-
"peerDependencies": {
86-
"class-transformer": "^0.2.3",
87-
"class-validator": "0.10.1"
88-
},
8989
"scripts": {
9090
"build": "rimraf build && echo Using TypeScript && tsc --version && tsc --pretty",
9191
"clean": "rimraf build coverage",

src/RoutingControllers.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ export class RoutingControllers<T extends BaseDriver> {
109109
* Executes given controller action.
110110
*/
111111
protected executeAction(actionMetadata: ActionMetadata, action: Action, interceptorFns: Function[]) {
112-
113112
// compute all parameters
114113
const paramsPromises = actionMetadata.params
115114
.sort((param1, param2) => param1.index - param2.index)
@@ -120,7 +119,7 @@ export class RoutingControllers<T extends BaseDriver> {
120119

121120
// execute action and handle result
122121
const allParams = actionMetadata.appendParams ? actionMetadata.appendParams(action).concat(params) : params;
123-
const result = actionMetadata.methodOverride ? actionMetadata.methodOverride(actionMetadata, action, allParams) : actionMetadata.callMethod(allParams);
122+
const result = actionMetadata.methodOverride ? actionMetadata.methodOverride(actionMetadata, action, allParams) : actionMetadata.callMethod(allParams, action);
124123
return this.handleCallMethodResult(result, actionMetadata, action, interceptorFns);
125124

126125
}).catch(error => {
@@ -172,7 +171,7 @@ export class RoutingControllers<T extends BaseDriver> {
172171
return uses.map(use => {
173172
if (use.interceptor.prototype && use.interceptor.prototype.intercept) { // if this is function instance of InterceptorInterface
174173
return function (action: Action, result: any) {
175-
return (getFromContainer(use.interceptor) as InterceptorInterface).intercept(action, result);
174+
return (getFromContainer(use.interceptor, action) as InterceptorInterface).intercept(action, result);
176175
};
177176
}
178177
return use.interceptor;

src/container.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Action } from "./Action";
12

23
/**
34
* Container options.
@@ -16,13 +17,15 @@ export interface UseContainerOptions {
1617

1718
}
1819

20+
export type ClassConstructor<T> = { new (...args: any[]): T };
21+
1922
/**
2023
* Container to be used by this library for inversion control. If container was not implicitly set then by default
2124
* container simply creates a new instance of the given class.
2225
*/
23-
const defaultContainer: { get<T>(someClass: { new (...args: any[]): T }|Function): T } = new (class {
26+
const defaultContainer: { get<T>(someClass: ClassConstructor<T> | Function): T } = new (class {
2427
private instances: { type: Function, object: any }[] = [];
25-
get<T>(someClass: { new (...args: any[]): T }): T {
28+
get<T>(someClass: ClassConstructor<T>): T {
2629
let instance = this.instances.find(instance => instance.type === someClass);
2730
if (!instance) {
2831
instance = { type: someClass, object: new someClass() };
@@ -33,24 +36,42 @@ const defaultContainer: { get<T>(someClass: { new (...args: any[]): T }|Function
3336
}
3437
})();
3538

36-
let userContainer: { get<T>(someClass: { new (...args: any[]): T }|Function): T };
39+
let userContainer: { get<T>(
40+
someClass: ClassConstructor<T> | Function,
41+
action?: Action
42+
): T };
3743
let userContainerOptions: UseContainerOptions;
3844

45+
/**
46+
* Allows routing controllers to resolve objects using your IoC container
47+
*/
48+
export interface IocAdapter {
49+
/**
50+
* Return
51+
*/
52+
get<T> (someClass: ClassConstructor<T>, action?: Action): T;
53+
}
54+
3955
/**
4056
* Sets container to be used by this library.
4157
*/
42-
export function useContainer(iocContainer: { get(someClass: any): any }, options?: UseContainerOptions) {
43-
userContainer = iocContainer;
58+
export function useContainer(iocAdapter: IocAdapter, options?: UseContainerOptions) {
59+
userContainer = iocAdapter;
4460
userContainerOptions = options;
4561
}
4662

4763
/**
4864
* Gets the IOC container used by this library.
65+
* @param someClass A class constructor to resolve
66+
* @param action The request/response context that `someClass` is being resolved for
4967
*/
50-
export function getFromContainer<T>(someClass: { new (...args: any[]): T }|Function): T {
68+
export function getFromContainer<T>(
69+
someClass: ClassConstructor<T> | Function,
70+
action?: Action
71+
): T {
5172
if (userContainer) {
5273
try {
53-
const instance = userContainer.get(someClass);
74+
const instance = userContainer.get(someClass, action);
5475
if (instance)
5576
return instance;
5677

src/driver/koa/KoaDriver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class KoaDriver extends BaseDriver {
7979
const action: Action = { request: context.request, response: context.response, context, next };
8080
try {
8181
const checkResult = actionMetadata.authorizedRoles instanceof Function ?
82-
getFromContainer<RoleChecker>(actionMetadata.authorizedRoles).check(action) :
82+
getFromContainer<RoleChecker>(actionMetadata.authorizedRoles, action).check(action) :
8383
this.authorizationChecker(action, actionMetadata.authorizedRoles);
8484

8585
const handleError = (result: any) => {
@@ -331,7 +331,7 @@ export class KoaDriver extends BaseDriver {
331331
if (use.middleware.prototype && use.middleware.prototype.use) { // if this is function instance of MiddlewareInterface
332332
middlewareFunctions.push((context: any, next: (err?: any) => Promise<any>) => {
333333
try {
334-
const useResult = (getFromContainer(use.middleware) as KoaMiddlewareInterface).use(context, next);
334+
const useResult = (getFromContainer(use.middleware, { context } as Action) as KoaMiddlewareInterface).use(context, next);
335335
if (isPromiseLike(useResult)) {
336336
useResult.catch((error: any) => {
337337
this.handleError(error, undefined, {

src/metadata/ActionMetadata.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ export class ActionMetadata {
260260
* Calls action method.
261261
* Action method is an action defined in a user controller.
262262
*/
263-
callMethod(params: any[]) {
264-
const controllerInstance = this.controllerMetadata.instance;
263+
callMethod(params: any[], action: Action) {
264+
const controllerInstance = this.controllerMetadata.getInstance(action);
265265
return controllerInstance[this.method].apply(controllerInstance, params);
266266
}
267267

src/metadata/ControllerMetadata.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {UseMetadata} from "./UseMetadata";
44
import {getFromContainer} from "../container";
55
import {ResponseHandlerMetadata} from "./ResponseHandleMetadata";
66
import {InterceptorMetadata} from "./InterceptorMetadata";
7+
import { Action } from "../Action";
78

89
/**
910
* Controller metadata.
@@ -70,9 +71,10 @@ export class ControllerMetadata {
7071

7172
/**
7273
* Gets instance of the controller.
74+
* @param action Details around the request session
7375
*/
74-
get instance(): any {
75-
return getFromContainer(this.target);
76+
getInstance(action: Action): any {
77+
return getFromContainer(this.target, action);
7678
}
7779

7880
// -------------------------------------------------------------------------

test/functional/container.spec.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import "reflect-metadata";
22
import {JsonController} from "../../src/decorator/JsonController";
3-
import {createExpressServer, createKoaServer, getMetadataArgsStorage} from "../../src/index";
3+
import {createExpressServer, createKoaServer, getMetadataArgsStorage, Action} from "../../src/index";
44
import {assertRequest} from "./test-utils";
55
import {Container, Service} from "typedi";
6-
import {useContainer} from "../../src/container";
6+
import {useContainer, IocAdapter, ClassConstructor} from "../../src/container";
77
import {Get} from "../../src/decorator/Get";
8+
import * as assert from "assert";
89
const chakram = require("chakram");
910
const expect = chakram.expect;
1011

@@ -104,17 +105,26 @@ describe("container", () => {
104105

105106
describe("using custom container should be possible", () => {
106107

108+
let fakeContainer: IocAdapter & {
109+
services: { [key: string]: any }
110+
context: any[]
111+
};
112+
107113
before(() => {
108114

109-
const fakeContainer = {
110-
services: [] as any,
115+
fakeContainer = {
116+
services: {},
117+
context: [],
118+
119+
get<T>(service: ClassConstructor<T>, action: Action): T {
111120

112-
get(service: any) {
121+
this.context.push(action.context);
122+
113123
if (!this.services[service.name]) {
114124
this.services[service.name] = new service();
115125
}
116126

117-
return this.services[service.name];
127+
return this.services[service.name] as T;
118128
}
119129
};
120130

@@ -206,6 +216,10 @@ describe("container", () => {
206216
title: "post #2"
207217
}]);
208218
});
219+
220+
it("should pass the action through to the Ioc adapter", () => {
221+
assert.notEqual(fakeContainer.context.length, 0);
222+
});
209223
});
210224

211225
describe("using custom container with fallback should be possible", () => {

0 commit comments

Comments
 (0)