Skip to content

Commit

Permalink
fix(mvc): Route order mechanism
Browse files Browse the repository at this point in the history
Closes: #29
  • Loading branch information
Romakita committed May 9, 2019
1 parent a86ac81 commit bba9d20
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 41 deletions.
4 changes: 2 additions & 2 deletions packages/common/src/filters/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ FilterPreHandlers.set(EXPRESS_ERR, locals => locals.err);
FilterPreHandlers.set(ENDPOINT_INFO, locals => {
const op = FilterPreHandlers.get(EXPRESS_REQUEST)!;

return op(locals).getEndpoint();
return op(locals).ctx.endpoint;
});
/**
* ResponseData PreHandler
*/
FilterPreHandlers.set(RESPONSE_DATA, locals => {
const op = FilterPreHandlers.get(EXPRESS_REQUEST)!;

return op(locals).getStoredData();
return op(locals).ctx.data;
});
43 changes: 28 additions & 15 deletions packages/common/src/mvc/class/ControllerBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ControllerProvider} from "../class/ControllerProvider";
import {EndpointMetadata} from "../class/EndpointMetadata";
import {bindEndpointMiddleware} from "../components/bindEndpointMiddleware";
import {SendResponseMiddleware} from "../components/SendResponseMiddleware";
import {IPathMethod} from "../interfaces/IPathMethod";
import {HandlerBuilder} from "./HandlerBuilder";

export class ControllerBuilder {
Expand All @@ -28,16 +29,35 @@ export class ControllerBuilder {
this.buildMiddlewares(injector, useBefore) // Controller before-middleware
.buildEndpoints(injector) // All endpoints and his middlewares
.buildMiddlewares(injector, useAfter) // Controller after-middleware
.buildSendResponse(injector) // Final middleware to send response
.buildChildrenCtrls(injector); // Children controllers

return this.provider.router;
}

private buildEndpoints(injector: InjectorService) {
const {endpoints} = this.provider;
const pathsMethodsMap: Map<string, IPathMethod> = new Map();

endpoints.forEach((endpoint: EndpointMetadata) => this.buildEndpoint(injector, endpoint));
endpoints.forEach(({pathsMethods}) => {
pathsMethods.forEach(pathMethod => {
pathMethod.method = pathMethod.method || "use";

if (pathMethod.method !== "use") {
const key = pathMethod.method + "-" + pathMethod.path;

if (pathsMethodsMap.has(key)) {
pathsMethodsMap.get(key)!.isFinal = false;
}

pathMethod.isFinal = true;
pathsMethodsMap.set(key, pathMethod);
}
});
});

endpoints.forEach(endpoint => {
this.buildEndpoint(injector, endpoint);
});

return this;
}
Expand All @@ -48,11 +68,11 @@ export class ControllerBuilder {
router,
middlewares: {use}
} = this.provider;

// Endpoint lifecycle
let handlers: any[] = [];

handlers = handlers
.concat(bindEndpointMiddleware(endpoint))
.concat(use) // Controller use-middlewares
.concat(beforeMiddlewares) // Endpoint before-middlewares
.concat(mldwrs) // Endpoint middlewares
Expand All @@ -61,16 +81,13 @@ export class ControllerBuilder {
.filter((item: any) => !!item)
.map((middleware: any) => HandlerBuilder.from(middleware).build(injector));

handlers = [bindEndpointMiddleware(endpoint)].concat(handlers);
const sendResponse = HandlerBuilder.from(SendResponseMiddleware).build(injector);

// Add handlers to the router
pathsMethods.forEach(({path, method}) => {
if (!!method && router[method]) {
router[method](path, ...handlers);
} else {
const args: any[] = [path].concat(handlers);
router.use(...args);
}
pathsMethods.forEach(({path, method, isFinal}) => {
const localHandlers = isFinal ? handlers.concat(sendResponse) : handlers;

router[method!](path, ...localHandlers);
});

if (!pathsMethods.length) {
Expand All @@ -95,10 +112,6 @@ export class ControllerBuilder {
});
}

private buildSendResponse(injector: InjectorService) {
return this.buildMiddlewares(injector, [SendResponseMiddleware]);
}

private buildMiddlewares(injector: InjectorService, middlewares: any[]) {
const {router} = this.provider;

Expand Down
8 changes: 4 additions & 4 deletions packages/common/src/mvc/class/EndpointMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {deepExtends, isArrayOrArrayClass, isPromise, Metadata, NotEnumerable, Storable, Store, Type} from "@tsed/core";
import {ParamRegistry} from "../../filters/registries/ParamRegistry";
import {EXPRESS_METHODS} from "../constants";
import {ExpressPathMethod} from "../interfaces/ExpressPathMethod";
import {IPathMethod} from "../interfaces/IPathMethod";
import {PathParamsType} from "../interfaces/PathParamsType";

/**
Expand All @@ -28,7 +28,7 @@ export class EndpointMetadata extends Storable {
/**
* Route strategy.
*/
public pathsMethods: ExpressPathMethod[] = [];
public pathsMethods: IPathMethod[] = [];
/**
* Endpoint inherited from parent class.
*/
Expand Down Expand Up @@ -57,7 +57,7 @@ export class EndpointMetadata extends Storable {
*/
set httpMethod(value: string) {
if (!this.pathsMethods[0]) {
this.pathsMethods[0] = {};
this.pathsMethods[0] = {} as any;
}

this.pathsMethods[0].method = value;
Expand All @@ -79,7 +79,7 @@ export class EndpointMetadata extends Storable {
*/
set path(value: PathParamsType) {
if (!this.pathsMethods[0]) {
this.pathsMethods[0] = {};
this.pathsMethods[0] = {} as any;
}
this.pathsMethods[0].path = value;
}
Expand Down
9 changes: 2 additions & 7 deletions packages/common/src/mvc/class/HandlerBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,11 @@ export class HandlerBuilder {
* @param err
*/
private async invoke(request: Express.Request, response: Express.Response, next: any, err?: any): Promise<any> {
const {hasEndpointInfo, hasNextFunction} = this.handlerMetadata;
const {hasNextFunction} = this.handlerMetadata;
const {
ctx: {endpoint, container}
ctx: {container}
} = request;

// Skip middleware when it use endpoint info without filled data
if (hasEndpointInfo && !endpoint) {
return next();
}

next = this.buildNext(request, response, next);

try {
Expand Down
2 changes: 0 additions & 2 deletions packages/common/src/mvc/class/HandlerMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export class HandlerMetadata {
readonly type: HandlerType = HandlerType.FUNCTION;
readonly hasErrorParam: boolean = false;
readonly hasNextFunction: boolean = false;
readonly hasEndpointInfo: boolean = false;
handler: any;

constructor(options: IHandlerOptions) {
Expand All @@ -35,7 +34,6 @@ export class HandlerMetadata {
this.methodClassName = method;
this.method = method;
this.hasNextFunction = this.hasParamType(EXPRESS_NEXT_FN);
this.hasEndpointInfo = this.hasParamType(ENDPOINT_INFO);
this.hasErrorParam = this.hasParamType(EXPRESS_ERR);
this.injectable = (Metadata.get(PARAM_METADATA, target, method) || []).length > 0;
}
Expand Down
6 changes: 0 additions & 6 deletions packages/common/src/mvc/interfaces/ExpressPathMethod.ts

This file was deleted.

7 changes: 7 additions & 0 deletions packages/common/src/mvc/interfaces/IPathMethod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {PathParamsType} from "./PathParamsType";

export interface IPathMethod {
path: PathParamsType;
isFinal?: boolean;
method?: string;
}
1 change: 1 addition & 0 deletions packages/common/src/mvc/utils/extendsRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if (!express.request.setEndpoint) {
* @deprecated Use request.ctx.enpoint
* @returns {any}
*/
// istanbul ignore next
getEndpoint() {
return this.ctx.endpoint;
},
Expand Down
10 changes: 5 additions & 5 deletions packages/common/test/mvc/class/ControllerBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ describe("ControllerBuilder", () => {
}];
endpoint.pathsMethods.push({
path: "/",
method: "get"
method: "get",
isFinal: true
});

// @ts-ignore
Expand Down Expand Up @@ -86,7 +87,7 @@ describe("ControllerBuilder", () => {

// THEN
result.should.to.eq(router);
router.use.callCount.should.deep.eq(4);
router.use.callCount.should.deep.eq(3);
router.use.getCall(0).should.have.been.calledWithExactly(provider.middlewares.useBefore[0]); // controller

// ENDPOINT
Expand All @@ -97,7 +98,8 @@ describe("ControllerBuilder", () => {
endpoint.beforeMiddlewares[0],
endpoint.middlewares[0],
endpoint,
endpoint.afterMiddlewares[0]
endpoint.afterMiddlewares[0],
SendResponseMiddleware
);
router.use.getCall(2).should.have.been.calledWithExactly(provider.middlewares.useAfter[0]); // controller
});
Expand Down Expand Up @@ -171,7 +173,6 @@ describe("ControllerBuilder", () => {
);

router.use.getCall(2).should.have.been.calledWithExactly(provider.middlewares.useAfter[0]); // controller
router.use.getCall(3).should.have.been.calledWithExactly(SendResponseMiddleware); // controller
});

it("should build controller (3)", () => {
Expand Down Expand Up @@ -239,6 +240,5 @@ describe("ControllerBuilder", () => {
);

router.use.getCall(2).should.have.been.calledWithExactly(provider.middlewares.useAfter[0]); // controller
router.use.getCall(3).should.have.been.calledWithExactly(SendResponseMiddleware); // controller
});
});

0 comments on commit bba9d20

Please sign in to comment.