diff --git a/integration/nest-application/global-prefix/e2e/global-prefix.spec.ts b/integration/nest-application/global-prefix/e2e/global-prefix.spec.ts index 4066d42842a..76acf712137 100644 --- a/integration/nest-application/global-prefix/e2e/global-prefix.spec.ts +++ b/integration/nest-application/global-prefix/e2e/global-prefix.spec.ts @@ -136,7 +136,9 @@ describe('Global prefix', () => { server = app.getHttpServer(); await app.init(); - await request(server).get('/').expect(200, '1'); + await request(server) + .get('/') + .expect(200, 'Extras: Data attached in middleware, Count: 1'); await request(server).get('/api/count').expect(200, '2'); }); diff --git a/integration/nest-application/global-prefix/src/app.controller.ts b/integration/nest-application/global-prefix/src/app.controller.ts index e62a1db2fcf..416ca649e5e 100644 --- a/integration/nest-application/global-prefix/src/app.controller.ts +++ b/integration/nest-application/global-prefix/src/app.controller.ts @@ -29,7 +29,7 @@ export class AppController { @Get() getHome(@Req() req) { - return req.count; + return 'Extras: ' + req.extras?.data + ', Count: ' + req.count; } @Get('count') diff --git a/packages/core/middleware/middleware-module.ts b/packages/core/middleware/middleware-module.ts index b0bf92a3fca..b956a23850f 100644 --- a/packages/core/middleware/middleware-module.ts +++ b/packages/core/middleware/middleware-module.ts @@ -190,12 +190,14 @@ export class MiddlewareModule< for (const metatype of middlewareCollection) { const collection = middlewareContainer.getMiddlewareCollection(moduleKey); const instanceWrapper = collection.get(metatype); + if (isUndefined(instanceWrapper)) { throw new RuntimeException(); } if (instanceWrapper.isTransient) { return; } + this.graphInspector.insertClassNode( moduleRef, instanceWrapper, diff --git a/packages/core/middleware/route-info-path-extractor.ts b/packages/core/middleware/route-info-path-extractor.ts index d8f17f5d954..263b12679db 100644 --- a/packages/core/middleware/route-info-path-extractor.ts +++ b/packages/core/middleware/route-info-path-extractor.ts @@ -35,11 +35,15 @@ export class RouteInfoPathExtractor { if (this.isAWildcard(path)) { const entries = versionPaths.length > 0 - ? versionPaths.map( - versionPath => + ? versionPaths + .map(versionPath => [ + this.prefixPath + versionPath + '$', this.prefixPath + versionPath + addLeadingSlash(path), - ) - : [this.prefixPath + addLeadingSlash(path)]; + ]) + .flat() + : this.prefixPath + ? [this.prefixPath + '$', this.prefixPath + addLeadingSlash(path)] + : [addLeadingSlash(path)]; return Array.isArray(this.excludedGlobalPrefixRoutes) ? [ diff --git a/packages/core/test/middleware/builder.spec.ts b/packages/core/test/middleware/builder.spec.ts index fa73acae66a..0f625f71496 100644 --- a/packages/core/test/middleware/builder.spec.ts +++ b/packages/core/test/middleware/builder.spec.ts @@ -193,7 +193,7 @@ describe('MiddlewareBuilder', () => { expect(proxy.getExcludedRoutes()).to.be.eql([ { path, - method: -1 as any, + method: -1, }, ]); }); diff --git a/packages/core/test/middleware/route-info-path-extractor.spec.ts b/packages/core/test/middleware/route-info-path-extractor.spec.ts index 0255cb9227c..62bfb5fc8d7 100644 --- a/packages/core/test/middleware/route-info-path-extractor.spec.ts +++ b/packages/core/test/middleware/route-info-path-extractor.spec.ts @@ -31,7 +31,7 @@ describe('RouteInfoPathExtractor', () => { method: RequestMethod.ALL, version: '1', }), - ).to.eql(['/v1/*']); + ).to.eql(['/v1$', '/v1/*']); }); it(`should return correct paths when set global prefix`, () => { @@ -42,7 +42,7 @@ describe('RouteInfoPathExtractor', () => { path: '*', method: RequestMethod.ALL, }), - ).to.eql(['/api/*']); + ).to.eql(['/api$', '/api/*']); expect( routeInfoPathExtractor.extractPathsFrom({ @@ -50,7 +50,7 @@ describe('RouteInfoPathExtractor', () => { method: RequestMethod.ALL, version: '1', }), - ).to.eql(['/api/v1/*']); + ).to.eql(['/api/v1$', '/api/v1/*']); }); it(`should return correct paths when set global prefix and global prefix options`, () => { @@ -66,7 +66,7 @@ describe('RouteInfoPathExtractor', () => { path: '*', method: RequestMethod.ALL, }), - ).to.eql(['/api/*', '/foo']); + ).to.eql(['/api$', '/api/*', '/foo']); expect( routeInfoPathExtractor.extractPathsFrom({ @@ -74,7 +74,7 @@ describe('RouteInfoPathExtractor', () => { method: RequestMethod.ALL, version: '1', }), - ).to.eql(['/api/v1/*', '/v1/foo']); + ).to.eql(['/api/v1$', '/api/v1/*', '/v1/foo']); expect( routeInfoPathExtractor.extractPathsFrom({ diff --git a/packages/platform-fastify/adapters/fastify-adapter.ts b/packages/platform-fastify/adapters/fastify-adapter.ts index 54e2df387e6..a2fb37046f8 100644 --- a/packages/platform-fastify/adapters/fastify-adapter.ts +++ b/packages/platform-fastify/adapters/fastify-adapter.ts @@ -47,15 +47,15 @@ import { import * as pathToRegexp from 'path-to-regexp'; // `querystring` is used internally in fastify for registering urlencoded body parser. import { parse as querystringParse } from 'querystring'; +import { + FASTIFY_ROUTE_CONFIG_METADATA, + FASTIFY_ROUTE_CONSTRAINTS_METADATA, +} from '../constants'; import { NestFastifyBodyParserOptions } from '../interfaces'; import { FastifyStaticOptions, FastifyViewOptions, } from '../interfaces/external'; -import { - FASTIFY_ROUTE_CONFIG_METADATA, - FASTIFY_ROUTE_CONSTRAINTS_METADATA, -} from '../constants'; type FastifyHttp2SecureOptions< Server extends http2.Http2SecureServer, @@ -554,6 +554,9 @@ export class FastifyAdapter< await this.registerMiddie(); } return (path: string, callback: Function) => { + const hasEndOfStringCharacter = path.endsWith('$'); + path = hasEndOfStringCharacter ? path.slice(0, -1) : path; + let normalizedPath = path.endsWith('/*') ? `${path.slice(0, -1)}(.*)` : path; @@ -561,7 +564,8 @@ export class FastifyAdapter< // Fallback to "(.*)" to support plugins like GraphQL normalizedPath = normalizedPath === '/(.*)' ? '(.*)' : normalizedPath; - const re = pathToRegexp(normalizedPath); + let re = pathToRegexp(normalizedPath); + re = hasEndOfStringCharacter ? new RegExp(re.source + '$', re.flags) : re; // The following type assertion is valid as we use import('@fastify/middie') rather than require('@fastify/middie') // ref https://github.com/fastify/middie/pull/55