Skip to content
This repository was archived by the owner on Jun 9, 2020. It is now read-only.

Commit b5b467f

Browse files
authored
fix(controller): Use the same controller context for routes inside a controller (#187)
Fixes #173. Fixes the typing errors with the decorators. Use the same context (controller instance) for all routes in a given Controller.
1 parent 4b06d36 commit b5b467f

21 files changed

Lines changed: 150 additions & 99 deletions

config/tsconfig.base.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"declaration": true,
1010
"sourceMap": false,
1111
"importHelpers": true,
12-
"strictNullChecks": true,
12+
"strict": true,
1313
"experimentalDecorators": true,
1414
"emitDecoratorMetadata": true,
1515
"noUnusedLocals": true,

src/Giuseppe.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const routeScore = (route: RouteRegisterInformation) =>
4141
export interface RouteRegisterInformation {
4242
route: GiuseppeRoute;
4343
ctrl: Function;
44+
instance: object;
4445
segments: number;
4546
wildcards: number;
4647
urlParams: number;
@@ -98,11 +99,11 @@ export class Giuseppe {
9899
protected routes: { [id: string]: RouteRegisterInformation } = {};
99100
protected _server: Server | undefined;
100101

101-
protected _returnTypes: ReturnType<any>[] | null;
102-
protected _pluginController: ControllerDefinitionConstructor[] | null;
103-
protected _pluginRoutes: RouteDefinitionConstructor[] | null;
104-
protected _pluginRouteModificators: RouteModificatorConstructor[] | null;
105-
protected _pluginParameters: ParameterDefinitionConstructor[] | null;
102+
protected _returnTypes: ReturnType<any>[] | null = null;
103+
protected _pluginController: ControllerDefinitionConstructor[] | null = null;
104+
protected _pluginRoutes: RouteDefinitionConstructor[] | null = null;
105+
protected _pluginRouteModificators: RouteModificatorConstructor[] | null = null;
106+
protected _pluginParameters: ParameterDefinitionConstructor[] | null = null;
106107

107108
/**
108109
* List of registered {@link ReturnType}.
@@ -344,6 +345,8 @@ export class Giuseppe {
344345
ctrlRoutes = ctrlRoutes.concat(modifiedRoutes);
345346
}
346347

348+
const ctrlInstance = new (ctrl.ctrlTarget as { new(...args: any[]): any; })();
349+
347350
for (const route of ctrlRoutes) {
348351
if (this.routes[route.id]) {
349352
throw new DuplicateRouteError(route);
@@ -354,6 +357,7 @@ export class Giuseppe {
354357
wildcards: route.url.split('*').length - 1,
355358
urlParams: route.url.split('/').filter(s => s.indexOf(':') >= 0).length,
356359
ctrl: ctrl.ctrlTarget,
360+
instance: ctrlInstance,
357361
};
358362
}
359363
}
@@ -363,7 +367,7 @@ export class Giuseppe {
363367
Object.keys(this.routes)
364368
.map(k => this.routes[k])
365369
.sort((a, b) => routeScore(b) - routeScore(a))
366-
.forEach(r => this.router[HttpMethod[r.route.method]](
370+
.forEach(r => (this.router as any)[HttpMethod[r.route.method]](
367371
`/${r.route.url}`,
368372
...r.route.middlewares,
369373
this.createRouteWrapper(r),
@@ -385,7 +389,6 @@ export class Giuseppe {
385389
const meta = new ControllerMetadata(routeInfo.ctrl.prototype);
386390
const params = meta.parameters(routeInfo.route.name);
387391
const returnTypeHandler = new ReturnTypeHandler(this.returnTypes);
388-
const ctrlInstance = new (routeInfo as any).ctrl();
389392

390393
return async (req: express.Request, res: express.Response) => {
391394
const paramValues: any[] = [];
@@ -395,7 +398,7 @@ export class Giuseppe {
395398
paramValues[param.index] = param.getValue(req, res);
396399
}
397400

398-
let result = routeInfo.route.function.apply(ctrlInstance, paramValues);
401+
let result = routeInfo.route.function.apply(routeInfo.instance, paramValues);
399402

400403
if (result instanceof Promise) {
401404
result = await result;
@@ -407,7 +410,7 @@ export class Giuseppe {
407410

408411
returnTypeHandler.handleValue(result, res);
409412
} catch (e) {
410-
meta.errorHandler().handleError(ctrlInstance, req, res, e);
413+
meta.errorHandler().handleError(routeInfo.instance, req, res, e);
411414
}
412415
};
413416
}

src/controller/ControllerDefinition.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { GiuseppeRoute } from '../routes/GiuseppeRoute';
55
/**
66
* Interface for a controller definition. Contains the targeted function (class) and containing middlewares.
77
* The definition must be able to create the routes that are registered within the controller.
8-
*
8+
*
99
* @export
1010
* @interface ControllerDefinition
1111
*/
1212
export interface ControllerDefinition {
1313
/**
1414
* The target class that is decorated with the controller decorator.
15-
*
15+
*
1616
* @type {Function}
1717
* @memberof ControllerDefinition
1818
*/
@@ -21,17 +21,17 @@ export interface ControllerDefinition {
2121
/**
2222
* A collection of middlewares that is contained in the given controller.
2323
* Middleware priority is: Controller -> Route (they are concatenated).
24-
*
24+
*
2525
* @type {RequestHandler[]}
2626
* @memberof ControllerDefinition
2727
*/
2828
readonly middlewares: RequestHandler[];
2929

3030
/**
3131
* A function that creates the routes for a given controller. Those routes are then modificated and registered.
32-
*
33-
* @param {string} baseUrl
34-
* @returns {GiuseppeRoute[]}
32+
*
33+
* @param {string} baseUrl
34+
* @returns {GiuseppeRoute[]}
3535
* @memberof ControllerDefinition
3636
*/
3737
createRoutes(baseUrl: string): GiuseppeRoute[];

src/core/controller/GiuseppeApiController.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { UrlHelper } from '../../utilities/UrlHelper';
1111
/**
1212
* Controller decorator. Creates a {@link GiuseppeApiController} that is registered within {@link Giuseppe}.
1313
* All controllers are later used to generate their routes.
14-
*
14+
*
1515
* @export
1616
* @param {(string | RequestHandler)} [routePrefixOrMiddleware] It's either a middleware (if no route prefix is used) or a
1717
* string that contains the routeprefix for this controller.
@@ -35,7 +35,7 @@ import { UrlHelper } from '../../utilities/UrlHelper';
3535
*/
3636
export function Controller(
3737
routePrefixOrMiddleware?: string | RequestHandler,
38-
...middlewares: RequestHandler[],
38+
...middlewares: RequestHandler[]
3939
): ClassDecorator {
4040
const routePrefix = routePrefixOrMiddleware && typeof routePrefixOrMiddleware === 'string' ?
4141
routePrefixOrMiddleware :
@@ -50,7 +50,7 @@ export function Controller(
5050

5151
/**
5252
* Default core controller of giuseppe. Contains the routes and generates them on "configureRouter()" of giuseppe.
53-
*
53+
*
5454
* @export
5555
* @class GiuseppeApiController
5656
* @implements {ControllerDefinition}

src/core/parameters/Body.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import { ParameterFactory, ParameterValidator } from './ParameterAdditions';
1010
/**
1111
* Parameter decorator. Creates a parameter decorator that is registered on that route. Can
1212
* contain a type factory and multiple validators.
13-
*
13+
*
1414
* @export
15-
* @param {{ validator?: ParameterValidator, factory?: ParameterFactory<any> }} [{ validator, factory } = {}]
16-
* @returns {ParameterDecorator}
15+
* @param {{ validator?: ParameterValidator, factory?: ParameterFactory<any> }} [{ validator, factory } = {}]
16+
* @returns {ParameterDecorator}
1717
*/
1818
export function Body(
1919
{
@@ -22,12 +22,12 @@ export function Body(
2222
factory,
2323
}: { required?: boolean, validator?: ParameterValidator, factory?: ParameterFactory<any> } = {},
2424
): ParameterDecorator {
25-
return (target: Object, propertyKey: string, parameterIndex: number) =>
25+
return (target: Object, propertyKey: string | symbol, parameterIndex: number) =>
2626
Giuseppe.registrar.registerParameter(
2727
target,
28-
propertyKey,
28+
propertyKey.toString(),
2929
new GiuseppeBodyParameter(
30-
new ControllerMetadata(target).parameterTypes(propertyKey)[parameterIndex],
30+
new ControllerMetadata(target).parameterTypes(propertyKey.toString())[parameterIndex],
3131
parameterIndex,
3232
required,
3333
validator,
@@ -38,7 +38,7 @@ export function Body(
3838

3939
/**
4040
* Default core body parameter of giuseppe. Injects Request.body into the route.
41-
*
41+
*
4242
* @export
4343
* @class GiuseppeBodyParameter
4444
* @extends {GiuseppeBaseParameter}

src/core/parameters/Cookie.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ParameterFactory, ParameterValidator } from './ParameterAdditions';
99

1010
/**
1111
* Class that splits cookie values into their specific parts.
12-
*
12+
*
1313
* @class CookieHelper
1414
*/
1515
class CookieHelper {
@@ -26,15 +26,15 @@ class CookieHelper {
2626
/**
2727
* Parameter decorator. Creates a parameter definition that injects a specific cookie from the request.
2828
* Can contain validators and a factory if the value is complex.
29-
*
29+
*
3030
* @export
3131
* @param {string} name Name of the cookie.
3232
* @param {{ required?: boolean, validator?: ParameterValidator, factory?: ParameterFactory<any> }} [{
3333
* required,
3434
* validator,
3535
* factory,
3636
* }={}] Configuration object for the cookie parameter.
37-
* @returns {ParameterDecorator}
37+
* @returns {ParameterDecorator}
3838
*/
3939
export function Cookie(
4040
name: string,
@@ -44,13 +44,13 @@ export function Cookie(
4444
factory,
4545
}: { required?: boolean, validator?: ParameterValidator, factory?: ParameterFactory<any> } = {},
4646
): ParameterDecorator {
47-
return (target: Object, propertyKey: string, parameterIndex: number) =>
47+
return (target: Object, propertyKey: string | symbol, parameterIndex: number) =>
4848
Giuseppe.registrar.registerParameter(
4949
target,
50-
propertyKey,
50+
propertyKey.toString(),
5151
new GiuseppeCookieParameter(
5252
name,
53-
new ControllerMetadata(target).parameterTypes(propertyKey)[parameterIndex],
53+
new ControllerMetadata(target).parameterTypes(propertyKey.toString())[parameterIndex],
5454
parameterIndex,
5555
required,
5656
validator,
@@ -61,7 +61,7 @@ export function Cookie(
6161

6262
/**
6363
* Default core cookie parameter of giuseppe. Injects the value of a specific cookie from the request.
64-
*
64+
*
6565
* @export
6666
* @class GiuseppeCookieParameter
6767
* @extends {GiuseppeBaseParameter}

src/core/parameters/GiuseppeBaseParameter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export abstract class GiuseppeBaseParameter implements ParameterDefinition {
5252
if (this.factory) {
5353
factory = this.factory;
5454
} else {
55-
factory = rawValue => {
55+
factory = (rawValue: any) => {
5656
const ctor = this.type as any;
5757
if (rawValue.constructor === ctor) {
5858
return rawValue;
@@ -76,7 +76,7 @@ export abstract class GiuseppeBaseParameter implements ParameterDefinition {
7676
if (!this.validator || (!this.required && (parsed === undefined || parsed === null))) {
7777
return;
7878
}
79-
const isValid = value => {
79+
const isValid = (value: any) => {
8080
const predicates = this.validator;
8181

8282
if (Array.isArray(predicates)) {

src/core/parameters/Header.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ import { ParameterFactory, ParameterValidator } from './ParameterAdditions';
1010
/**
1111
* Parameter decorator. Creates a parameter definition that injects a specific header value from the request.
1212
* Can contain validators and a factory if the value is complex.
13-
*
13+
*
1414
* @export
15-
* @param {string} name
15+
* @param {string} name
1616
* @param {{ required?: boolean, validator?: ParameterValidator, factory?: ParameterFactory<any> }} [{
1717
* required,
1818
* validator,
1919
* factory,
20-
* }={}]
21-
* @returns {ParameterDecorator}
20+
* }={}]
21+
* @returns {ParameterDecorator}
2222
*/
2323
export function Header(
2424
name: string,
@@ -28,13 +28,13 @@ export function Header(
2828
factory,
2929
}: { required?: boolean, validator?: ParameterValidator, factory?: ParameterFactory<any> } = {},
3030
): ParameterDecorator {
31-
return (target: Object, propertyKey: string, parameterIndex: number) =>
31+
return (target: Object, propertyKey: string | symbol, parameterIndex: number) =>
3232
Giuseppe.registrar.registerParameter(
3333
target,
34-
propertyKey,
34+
propertyKey.toString(),
3535
new GiuseppeHeaderParameter(
3636
name,
37-
new ControllerMetadata(target).parameterTypes(propertyKey)[parameterIndex],
37+
new ControllerMetadata(target).parameterTypes(propertyKey.toString())[parameterIndex],
3838
parameterIndex,
3939
required,
4040
validator,
@@ -45,7 +45,7 @@ export function Header(
4545

4646
/**
4747
* Default core header parameter of giuseppe. Injects a specific header value into the route.
48-
*
48+
*
4949
* @export
5050
* @class GiuseppeHeaderParameter
5151
* @extends {GiuseppeBaseParameter}

src/core/parameters/ParameterAdditions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ export function isNumber({ min, max, multipleOf }: { min?: number, max?: number,
6262
return false;
6363
}
6464

65-
if (!isNullOrUndefined(min) && value < min) {
65+
if (!isNullOrUndefined(min) && value < min!) {
6666
return false;
6767
}
6868

69-
if (!isNullOrUndefined(max) && value > max) {
69+
if (!isNullOrUndefined(max) && value > max!) {
7070
return false;
7171
}
7272

73-
return !(!isNullOrUndefined(multipleOf) && value % multipleOf !== 0);
73+
return !(!isNullOrUndefined(multipleOf) && value % multipleOf! !== 0);
7474
};
7575
}
7676

@@ -93,11 +93,11 @@ export function isArray(
9393
return false;
9494
}
9595

96-
if (!isNullOrUndefined(min) && value.length < min) {
96+
if (!isNullOrUndefined(min) && value.length < min!) {
9797
return false;
9898
}
9999

100-
if (!isNullOrUndefined(max) && value.length > max) {
100+
if (!isNullOrUndefined(max) && value.length > max!) {
101101
return false;
102102
}
103103

src/core/parameters/Query.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ParameterFactory, ParameterValidator } from './ParameterAdditions';
99

1010
/**
1111
* @typedef QueryConfigObject
12-
12+
1313
* @property {string | string[]} [alias]
1414
* @property {boolean} [required]
1515
* @property {ParameterValidator} [validator]
@@ -20,11 +20,11 @@ import { ParameterFactory, ParameterValidator } from './ParameterAdditions';
2020
* Parameter decorator. Creates a parameter definition that injects a query parameter value from the request.
2121
* Can contain validators and a factory if the value is complex. If an alias is defined, the alias(es)
2222
* will be used to determine a value other than the given name.
23-
*
23+
*
2424
* @export
25-
* @param {string} name
25+
* @param {string} name
2626
* @param {QueryConfigObject} [{alias, required, validator, factory}={}]
27-
* @returns {ParameterDecorator}
27+
* @returns {ParameterDecorator}
2828
*/
2929
export function Query(
3030
name: string,
@@ -41,13 +41,13 @@ export function Query(
4141
factory?: ParameterFactory<any>,
4242
} = {},
4343
): ParameterDecorator {
44-
return (target: Object, propertyKey: string, parameterIndex: number) =>
44+
return (target: Object, propertyKey: string | symbol, parameterIndex: number) =>
4545
Giuseppe.registrar.registerParameter(
4646
target,
47-
propertyKey,
47+
propertyKey.toString(),
4848
new GiuseppeQueryParameter(
4949
name,
50-
new ControllerMetadata(target).parameterTypes(propertyKey)[parameterIndex],
50+
new ControllerMetadata(target).parameterTypes(propertyKey.toString())[parameterIndex],
5151
parameterIndex,
5252
required,
5353
validator,
@@ -60,7 +60,7 @@ export function Query(
6060
/**
6161
* Default core query parameter of giuseppe. Does inject a query parameter from the request into the route.
6262
* Can contain an alias that the query parameter can be named with.
63-
*
63+
*
6464
* @export
6565
* @class GiuseppeQueryParameter
6666
* @extends {GiuseppeBaseParameter}

0 commit comments

Comments
 (0)