Skip to content

Commit

Permalink
Implemented route map util (#88)
Browse files Browse the repository at this point in the history
* Implemented route map util

* Renamed path

* lock dep
  • Loading branch information
remojansen authored Dec 7, 2017
1 parent b4a4f42 commit 992ebd8
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 48 deletions.
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,89 @@ container.bind<interfaces.Controller>(TYPE.Controller)
.whenTargetNamed("UserDetailsController");
```

## Route Map

If we have some controllers like for example:

```ts
@controller("/api/user")
class UserController extends BaseHttpController {
@httpGet("/")
public get() {
return {};
}
@httpPost("/")
public post() {
return {};
}
@httpDelete("/:id")
public delete(@requestParam("id") id: string) {
return {};
}
}

@controller("/api/order")
class OrderController extends BaseHttpController {
@httpGet("/")
public get() {
return {};
}
@httpPost("/")
public post() {
return {};
}
@httpDelete("/:id")
public delete(@requestParam("id") id: string) {
return {};
}
}
```

We can use the `prettyjson` function to see all the available enpoints:

```ts
import { getRouteInfo } from "inversify-express-utils";
import * as prettyjson from "prettyjson";

// ...

let server = new InversifyExpressServer(container);
let app = server.build();
const routeInfo = getRouteInfo(container);

console.log(prettyjson.render({ routes: routeInfo }));

// ...
```

The output formatter by `prettyjson` looks as follows:

```txt
routes:
-
controller: Symbol(OrderController)
endpoints:
-
route: GET /api/order/
-
route: POST /api/order/
-
path: DELETE /api/order/:id
route:
- @requestParam id
-
controller: Symbol(UserController)
endpoints:
-
route: GET /api/user/
-
route: POST /api/user/
-
route: DELETE /api/user/:id
args:
- @requestParam id
```

## Examples

Some examples can be found at the [inversify-express-example](https://github.com/inversify/inversify-express-example) repository.
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "inversify-express-utils",
"version": "5.0.0",
"version": "5.1.0",
"description": "Some utilities for the development of express applications with Inversify",
"main": "lib/index.js",
"jsnext:main": "es/index.js",
Expand Down Expand Up @@ -31,6 +31,7 @@
"@types/cookie-parser": "1.4.1",
"@types/express": "4.0.39",
"@types/mocha": "2.2.44",
"@types/prettyjson": "0.0.28",
"@types/sinon": "4.1.0",
"@types/supertest": "2.0.4",
"bluebird": "3.5.1",
Expand All @@ -44,11 +45,12 @@
"gulp-typescript": "3.2.3",
"inversify": "4.6.0",
"mocha": "4.0.1",
"prettyjson": "1.2.1",
"publish-please": "2.3.1",
"reflect-metadata": "0.1.10",
"run-sequence": "2.2.0",
"source-map-support": "0.5.0",
"sinon": "4.1.2",
"source-map-support": "0.5.0",
"supertest": "3.0.0",
"tslint": "5.8.0",
"typescript": "2.6.2"
Expand Down
6 changes: 3 additions & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const TYPE = {
AuthProvider: Symbol("AuthProvider"),
Controller: Symbol("Controller"),
HttpContext: Symbol("HttpContext")
AuthProvider: Symbol.for("AuthProvider"),
Controller: Symbol.for("Controller"),
HttpContext: Symbol.for("HttpContext")
};

const METADATA_KEY = {
Expand Down
107 changes: 107 additions & 0 deletions src/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { interfaces as inversifyInterfaces } from "inversify";
import { BaseHttpController } from "./base_http_controller";
import { interfaces } from "./interfaces";
import { PARAMETER_TYPE } from "./constants";
import {
getControllersFromContainer,
getControllerMetadata,
getControllerMethodMetadata,
getControllerParameterMetadata
} from "./utils";

export function getRouteInfo(container: inversifyInterfaces.Container) {

const raw = getRawMetadata(container);

const info = raw.map(r => {

const controllerId = Symbol.for(r.controllerMetadata.target.name).toString();

const endpoints = r.methodMetadata.map(m => {

const method = m.method.toUpperCase();
const controllerPath = r.controllerMetadata.path;
const actionPath = m.path;
const paramMetadata = r.parameterMetadata[m.key] || undefined;
let args: string[] | undefined = undefined;

if (paramMetadata) {
args = (r.parameterMetadata[m.key] || []).map(a => {
let type = "";
switch (a.type) {
case PARAMETER_TYPE.RESPONSE:
type = "@response";
break;
case PARAMETER_TYPE.REQUEST:
type = "@request";
break;
case PARAMETER_TYPE.NEXT:
type = "@next";
break;
case PARAMETER_TYPE.PARAMS:
type = "@requestParam";
break;
case PARAMETER_TYPE.QUERY:
type = "queryParam";
break;
case PARAMETER_TYPE.BODY:
type = "@requestBody";
break;
case PARAMETER_TYPE.HEADERS:
type = "@requestHeaders";
break;
case PARAMETER_TYPE.COOKIES:
type = "@cookies";
break;
}
return `${type} ${a.parameterName}`;
});
}

const details = {
route: `${method} ${controllerPath}${actionPath}`
};

if (args) {
details["args"] = args;
}

return details as { route: string, args?: string[] };

});

return {
controller: controllerId,
endpoints: endpoints
};

});

return info;

}

export function getRawMetadata(container: inversifyInterfaces.Container) {

const controllers = getControllersFromContainer(container);

const raw = controllers.map((controller) => {

let constructor = controller.constructor;
let controllerMetadata: interfaces.ControllerMetadata = getControllerMetadata(constructor);
let methodMetadata: interfaces.ControllerMethodMetadata[] = getControllerMethodMetadata(constructor);
let parameterMetadata: interfaces.ControllerParameterMetadata = getControllerParameterMetadata(constructor);

return {
controllerMetadata,
methodMetadata,
parameterMetadata
};

});

return raw;

}


12 changes: 6 additions & 6 deletions src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,27 @@ export function controller(path: string, ...middleware: interfaces.Middleware[])
};
}

export function all (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function all(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("all", path, ...middleware);
}

export function httpGet (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function httpGet(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("get", path, ...middleware);
}

export function httpPost (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function httpPost(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("post", path, ...middleware);
}

export function httpPut (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function httpPut(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("put", path, ...middleware);
}

export function httpPatch (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function httpPatch(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("patch", path, ...middleware);
}

export function httpHead (path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
export function httpHead(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator {
return httpMethod("head", path, ...middleware);
}

Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import { interfaces } from "./interfaces";
import { BaseHttpController } from "./base_http_controller";
import { BaseMiddleware } from "./base_middleware";
import { cleanUpMetadata } from "./utils";
import { getRouteInfo, getRawMetadata } from "./debug";

export {
getRouteInfo,
getRawMetadata,
cleanUpMetadata,
interfaces,
InversifyExpressServer,
Expand Down
45 changes: 18 additions & 27 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import * as express from "express";
import * as inversify from "inversify";
import { interfaces } from "./interfaces";
import { BaseMiddleware } from "./index";
import {
getControllersFromMetadata,
getControllersFromContainer,
getControllerMetadata,
getControllerMethodMetadata,
getControllerParameterMetadata
} from "./utils";
import {
TYPE,
METADATA_KEY,
Expand All @@ -10,9 +17,6 @@ import {
DUPLICATED_CONTROLLER_NAME
} from "./constants";

/**
* Wrapper for the express server.
*/
export class InversifyExpressServer {

private _router: express.Router;
Expand Down Expand Up @@ -120,41 +124,28 @@ export class InversifyExpressServer {
// Fake HttpContext is needed during registration
this._container.bind<interfaces.HttpContext>(TYPE.HttpContext).toConstantValue({} as any);

let arrayOfControllerMetadata: interfaces.ControllerMetadata[] = Reflect.getMetadata(
METADATA_KEY.controller,
Reflect
) || [];
let constructors = getControllersFromMetadata();

constructors.forEach((constructor) => {

arrayOfControllerMetadata.forEach((metadata) => {
const constructor = metadata.target;
const name = constructor.name;

if (this._container.isBoundNamed(TYPE.Controller, metadata.target.name)) {
throw new Error(DUPLICATED_CONTROLLER_NAME(metadata.target.name));
if (this._container.isBoundNamed(TYPE.Controller, name)) {
throw new Error(DUPLICATED_CONTROLLER_NAME(name));
}

this._container.bind(TYPE.Controller)
.to(constructor)
.whenTargetNamed(metadata.target.name);
.whenTargetNamed(name);
});

let controllers: interfaces.Controller[] = this._container.getAll<interfaces.Controller>(TYPE.Controller);
let controllers = getControllersFromContainer(this._container);

controllers.forEach((controller: interfaces.Controller) => {

let controllerMetadata: interfaces.ControllerMetadata = Reflect.getOwnMetadata(
METADATA_KEY.controller,
controller.constructor
);

let methodMetadata: interfaces.ControllerMethodMetadata[] = Reflect.getOwnMetadata(
METADATA_KEY.controllerMethod,
controller.constructor
);

let parameterMetadata: interfaces.ControllerParameterMetadata = Reflect.getOwnMetadata(
METADATA_KEY.controllerParameter,
controller.constructor
);
let controllerMetadata = getControllerMetadata(controller.constructor);
let methodMetadata = getControllerMethodMetadata(controller.constructor);
let parameterMetadata = getControllerParameterMetadata(controller.constructor);

if (controllerMetadata && methodMetadata) {

Expand Down
Loading

0 comments on commit 992ebd8

Please sign in to comment.