diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index 6f3cf4e244f..7c8dda3e07b 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -353,6 +353,22 @@ on [Response filters](/docs/response-filter.md). Object configure Multer. See more on [Upload file](/tutorials/serve-static-files.md). +## router + +```typescript +@Configuration({ + router: { + appendChildrenRoutesFirst: true + } +}) +``` + +### router.appendChildrenRoutesFirst + +- type: `boolean` + +Append children routes before the controller routes itself. Defaults to `false`, but will be deprecated and set to `true` in next major version. + ## jsonMapper ```typescript diff --git a/packages/platform/common/src/config/interfaces/PlatformRouterSettings.ts b/packages/platform/common/src/config/interfaces/PlatformRouterSettings.ts new file mode 100644 index 00000000000..6b4cf9868ef --- /dev/null +++ b/packages/platform/common/src/config/interfaces/PlatformRouterSettings.ts @@ -0,0 +1,11 @@ +export interface PlatformRouterSettings { + appendChildrenRoutesFirst?: boolean; +} + +declare global { + namespace TsED { + interface Configuration extends Record { + router?: PlatformRouterSettings; + } + } +} diff --git a/packages/platform/platform-router/src/domain/PlatformRouters.ts b/packages/platform/platform-router/src/domain/PlatformRouters.ts index 7980ec604f5..2347a43bebb 100644 --- a/packages/platform/platform-router/src/domain/PlatformRouters.ts +++ b/packages/platform/platform-router/src/domain/PlatformRouters.ts @@ -75,9 +75,19 @@ export class PlatformRouters { } const useBefore = getValue(provider, "middlewares.useBefore", []); - + const middlewares: any[] = [...parentMiddlewares, ...useBefore]; const {children} = provider; + // Set default to true in next major version + const appendChildrenRoutesFirst = this.injector.settings.get('router.appendChildrenRoutesFirst', false) + + if (appendChildrenRoutesFirst) { + children.forEach((token: Type) => { + const nested = this.from(token, middlewares); + router.use(nested); + }); + } + getOperationsRoutes(provider.token, {allowedVerbs: this.allowedVerbs}).forEach((operationRoute) => { const {endpoint} = operationRoute; const {beforeMiddlewares, middlewares: mldwrs, afterMiddlewares} = endpoint; @@ -112,13 +122,12 @@ export class PlatformRouters { ); }); - const middlewares: any[] = [...parentMiddlewares, ...useBefore]; - - children.forEach((token: Type) => { - const nested = this.from(token, middlewares); - - router.use(nested); - }); + if (!appendChildrenRoutesFirst) { + children.forEach((token: Type) => { + const nested = this.from(token, middlewares); + router.use(nested); + }); + } return router; } diff --git a/packages/platform/platform-router/test/routers-nested.integration.spec.ts b/packages/platform/platform-router/test/routers-nested.integration.spec.ts index 7ac0194c760..91d284d81b9 100644 --- a/packages/platform/platform-router/test/routers-nested.integration.spec.ts +++ b/packages/platform/platform-router/test/routers-nested.integration.spec.ts @@ -58,6 +58,7 @@ function createAppRouterFixture() { describe("routers integration", () => { beforeEach(() => PlatformTest.create()); afterEach(() => PlatformTest.reset()); + describe("getLayers()", () => { it("should declare router", () => { const {platformRouters, appRouter} = createAppRouterFixture(); @@ -99,5 +100,47 @@ describe("routers integration", () => { "/rest/platform/:platform/comments" ]); }); + + it('should declare correctly with appendChildrenRoutesFirst', () => { + const {injector, platformRouters, appRouter} = createAppRouterFixture(); + injector.settings.set('router.appendChildrenRoutesFirst', true); + + platformRouters.prebuild(); + + appRouter.use("/rest", platformRouters.from(DomainController)); + appRouter.use("/rest", platformRouters.from(PlatformController)); + + const layers = platformRouters.getLayers(appRouter); + + expect( + layers.map((layer) => { + return layer.inspect().path; + }) + ).toEqual([ + "/rest/domain/:contextID/comments/flag", + "/rest/domain/:contextID/comments/:commentID/flag", + "/rest/domain/:contextID/comments", + "/rest/domain/:contextID", + "/rest/platform/:platform/comments/flag", + "/rest/platform/:platform/comments/:commentID/flag", + "/rest/platform/:platform/comments", + "/rest/platform/:platform" + ]); + + expect( + layers.map((layer) => { + return layer.getBasePath(); + }) + ).toEqual([ + "/rest/domain/:contextID/comments", + "/rest/domain/:contextID/comments", + "/rest/domain/:contextID", + "/rest", + "/rest/platform/:platform/comments", + "/rest/platform/:platform/comments", + "/rest/platform/:platform", + "/rest" + ]); + }); }); });