diff --git a/README.md b/README.md index 83b0295a..0b919e7c 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,16 @@ let router = express.Router({ let server = new InversifyExpressServer(container, router); ``` +By default server will serve the API at `/` path, but sometimes you might need to use different root namespace, for +example all routes should start with `/api/v1`. It is possible to pass this setting via routing configuration to +`InversifyExpressServer` + +```ts +let container = new Container(); + +let server = new InversifyExpressServer(container, null, { rootPath: "/api/v1" }); +``` + ## Decorators ### `@Controller(path, [middleware, ...])` diff --git a/src/constants.ts b/src/constants.ts index 5b42c516..5b0a309e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,4 +7,6 @@ const METADATA_KEY = { controllerMethod: "_controller-method" }; -export { TYPE, METADATA_KEY }; +const DEFAULT_ROUTING_ROOT_PATH = "/"; + +export { TYPE, METADATA_KEY, DEFAULT_ROUTING_ROOT_PATH }; diff --git a/src/interfaces.ts b/src/interfaces.ts index 143a7c63..7827ac90 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -23,6 +23,10 @@ namespace interfaces { (app: express.Application): void; } + export interface RoutingConfig { + rootPath: string; + } + } export { interfaces }; diff --git a/src/server.ts b/src/server.ts index eabbe0ae..9c2c2695 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,7 @@ import * as express from "express"; import * as inversify from "inversify"; import { interfaces } from "./interfaces"; -import { TYPE, METADATA_KEY } from "./constants"; +import { TYPE, METADATA_KEY, DEFAULT_ROUTING_ROOT_PATH } from "./constants"; /** * Wrapper for the express server. @@ -13,6 +13,7 @@ export class InversifyExpressServer { private _app: express.Application = express(); private _configFn: interfaces.ConfigFunction; private _errorConfigFn: interfaces.ConfigFunction; + private _routingConfig: interfaces.RoutingConfig; /** * Wrapper for the express server. @@ -21,10 +22,14 @@ export class InversifyExpressServer { */ constructor( container: inversify.interfaces.Container, - customRouter?: express.Router + customRouter?: express.Router, + routingConfig?: interfaces.RoutingConfig ) { this._container = container; this._router = customRouter || express.Router(); + this._routingConfig = routingConfig || { + rootPath: DEFAULT_ROUTING_ROOT_PATH + }; } /** @@ -93,12 +98,17 @@ export class InversifyExpressServer { methodMetadata.forEach((metadata: interfaces.ControllerMethodMetadata) => { let handler: express.RequestHandler = this.handlerFactory(controllerMetadata.target.name, metadata.key); - router[metadata.method](metadata.path, ...metadata.middleware, handler); + this._router[metadata.method]( + `${controllerMetadata.path}${metadata.path}`, + ...controllerMetadata.middleware, + ...metadata.middleware, + handler + ); }); - - this._app.use(controllerMetadata.path, ...controllerMetadata.middleware, router); } }); + + this._app.use(this._routingConfig.rootPath, this._router); } private handlerFactory(controllerName: any, key: string): express.RequestHandler { diff --git a/test/framework.test.ts b/test/framework.test.ts index f4367a54..0188a1be 100644 --- a/test/framework.test.ts +++ b/test/framework.test.ts @@ -186,6 +186,60 @@ describe("Integration Tests:", () => { .get("/") .expect(200, JSON.stringify(result), done); }); + + it("should use custom router passed from configuration", () => { + @injectable() + @Controller("/CaseSensitive") + class TestController { + @Get("/Endpoint") public get() { + return "Such Text"; + } + } + container.bind(TYPE.Controller).to(TestController).whenTargetNamed("TestController"); + + const customRouter = express.Router({ + caseSensitive: true + }); + + server = new InversifyExpressServer(container, customRouter); + const app = server.build(); + + const expectedSuccess = request(app) + .get("/CaseSensitive/Endpoint") + .expect(200, "Such Text"); + + const expectedNotFound1 = request(app) + .get("/casesensitive/endpoint") + .expect(404); + + const expectedNotFound2 = request(app) + .get("/CaseSensitive/endpoint") + .expect(404); + + return Promise.all([ + expectedSuccess, + expectedNotFound1, + expectedNotFound2 + ]); + + }); + + it("should use custom routing configuration", () => { + @injectable() + @Controller("/ping") + class TestController { + @Get("/endpoint") public get() { + return "pong"; + } + } + container.bind(TYPE.Controller).to(TestController).whenTargetNamed("TestController"); + + server = new InversifyExpressServer(container, null, { rootPath: "/api/v1" }); + + return request(server.build()) + .get("/api/v1/ping/endpoint") + .expect(200, "pong"); + }); }); diff --git a/test/server.test.ts b/test/server.test.ts index 31cf1474..a9b00a5e 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -54,4 +54,22 @@ describe("Unit Test: InversifyExpressServer", () => { }); + it("Should allow to provide custom routing configuration", () => { + + let container = new Container(); + + let routingConfig = { + rootPath: "/such/root/path" + }; + + let serverWithDefaultConfig = new InversifyExpressServer(container); + let serverWithCustomConfig = new InversifyExpressServer(container, null, routingConfig); + + expect((serverWithCustomConfig as any)._routingConfig).to.eq(routingConfig); + expect((serverWithDefaultConfig as any)._routingConfig).to.not.eql( + (serverWithCustomConfig as any)._routingConfig + ); + + }); + });