Skip to content

Commit 3321f6c

Browse files
fix(core): middleware is not executed for root route with prefix
1 parent 7d8822c commit 3321f6c

File tree

8 files changed

+24
-26
lines changed

8 files changed

+24
-26
lines changed

integration/nest-application/global-prefix/e2e/global-prefix.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ describe('Global prefix', () => {
2828
await request(server).get('/health').expect(404);
2929

3030
await request(server).get('/api/v1/health').expect(200);
31-
32-
await request(server)
33-
.get('/api/v1')
34-
.expect(200, 'Root: Data attached in middleware');
3531
});
3632

3733
it(`should exclude the path as string`, async () => {
@@ -140,7 +136,9 @@ describe('Global prefix', () => {
140136
server = app.getHttpServer();
141137
await app.init();
142138

143-
await request(server).get('/').expect(200, '1');
139+
await request(server)
140+
.get('/')
141+
.expect(200, 'Extras: Data attached in middleware, Count: 1');
144142
await request(server).get('/api/count').expect(200, '2');
145143
});
146144

integration/nest-application/global-prefix/src/app.controller.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ import { Controller, Get, Post, Req } from '@nestjs/common';
22

33
@Controller()
44
export class AppController {
5-
@Get()
6-
root(@Req() req): string {
7-
return 'Root: ' + req.extras?.data;
8-
}
9-
105
@Get('hello/:name')
116
getHello(@Req() req): string {
127
return 'Hello: ' + req.extras?.data;
@@ -34,7 +29,7 @@ export class AppController {
3429

3530
@Get()
3631
getHome(@Req() req) {
37-
return req.count;
32+
return 'Extras: ' + req.extras?.data + ', Count: ' + req.count;
3833
}
3934

4035
@Get('count')

packages/core/middleware/middleware-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,14 @@ export class MiddlewareModule<
190190
for (const metatype of middlewareCollection) {
191191
const collection = middlewareContainer.getMiddlewareCollection(moduleKey);
192192
const instanceWrapper = collection.get(metatype);
193+
193194
if (isUndefined(instanceWrapper)) {
194195
throw new RuntimeException();
195196
}
196197
if (instanceWrapper.isTransient) {
197198
return;
198199
}
200+
199201
this.graphInspector.insertClassNode(
200202
moduleRef,
201203
instanceWrapper,

packages/core/middleware/route-info-path-extractor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ export class RouteInfoPathExtractor {
3737
versionPaths.length > 0
3838
? versionPaths
3939
.map(versionPath => [
40-
this.prefixPath + versionPath,
40+
this.prefixPath + versionPath + '$',
4141
this.prefixPath + versionPath + addLeadingSlash(path),
4242
])
4343
.flat()
4444
: this.prefixPath
45-
? [this.prefixPath, this.prefixPath + addLeadingSlash(path)]
45+
? [this.prefixPath + '$', this.prefixPath + addLeadingSlash(path)]
4646
: [addLeadingSlash(path)];
4747

4848
return Array.isArray(this.excludedGlobalPrefixRoutes)

packages/core/middleware/routes-mapper.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { Module } from '../injector/module';
2020
import { MetadataScanner } from '../metadata-scanner';
2121
import { PathsExplorer, RouteDefinition } from '../router/paths-explorer';
2222
import { targetModulesByContainer } from '../router/router-module';
23-
import { RequestMethod } from '@nestjs/common';
2423

2524
export class RoutesMapper {
2625
private readonly pathsExplorer: PathsExplorer;
@@ -47,7 +46,7 @@ export class RoutesMapper {
4746
}
4847

4948
private getRouteInfoFromPath(routePath: string): RouteInfo[] {
50-
const defaultRequestMethod = RequestMethod.ALL;
49+
const defaultRequestMethod = -1;
5150
return [
5251
{
5352
path: addLeadingSlash(routePath),

packages/core/test/middleware/builder.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ describe('MiddlewareBuilder', () => {
193193
expect(proxy.getExcludedRoutes()).to.be.eql([
194194
{
195195
path,
196-
method: RequestMethod.ALL,
196+
method: -1,
197197
},
198198
]);
199199
});

packages/core/test/middleware/route-info-path-extractor.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('RouteInfoPathExtractor', () => {
3131
method: RequestMethod.ALL,
3232
version: '1',
3333
}),
34-
).to.eql(['/v1', '/v1/*']);
34+
).to.eql(['/v1$', '/v1/*']);
3535
});
3636

3737
it(`should return correct paths when set global prefix`, () => {
@@ -42,15 +42,15 @@ describe('RouteInfoPathExtractor', () => {
4242
path: '*',
4343
method: RequestMethod.ALL,
4444
}),
45-
).to.eql(['/api', '/api/*']);
45+
).to.eql(['/api$', '/api/*']);
4646

4747
expect(
4848
routeInfoPathExtractor.extractPathsFrom({
4949
path: '*',
5050
method: RequestMethod.ALL,
5151
version: '1',
5252
}),
53-
).to.eql(['/api/v1', '/api/v1/*']);
53+
).to.eql(['/api/v1$', '/api/v1/*']);
5454
});
5555

5656
it(`should return correct paths when set global prefix and global prefix options`, () => {
@@ -66,15 +66,15 @@ describe('RouteInfoPathExtractor', () => {
6666
path: '*',
6767
method: RequestMethod.ALL,
6868
}),
69-
).to.eql(['/api', '/api/*', '/foo']);
69+
).to.eql(['/api$', '/api/*', '/foo']);
7070

7171
expect(
7272
routeInfoPathExtractor.extractPathsFrom({
7373
path: '*',
7474
method: RequestMethod.ALL,
7575
version: '1',
7676
}),
77-
).to.eql(['/api/v1', '/api/v1/*', '/v1/foo']);
77+
).to.eql(['/api/v1$', '/api/v1/*', '/v1/foo']);
7878

7979
expect(
8080
routeInfoPathExtractor.extractPathsFrom({

packages/platform-fastify/adapters/fastify-adapter.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ import {
4747
import * as pathToRegexp from 'path-to-regexp';
4848
// `querystring` is used internally in fastify for registering urlencoded body parser.
4949
import { parse as querystringParse } from 'querystring';
50+
import {
51+
FASTIFY_ROUTE_CONFIG_METADATA,
52+
FASTIFY_ROUTE_CONSTRAINTS_METADATA,
53+
} from '../constants';
5054
import { NestFastifyBodyParserOptions } from '../interfaces';
5155
import {
5256
FastifyStaticOptions,
5357
FastifyViewOptions,
5458
} from '../interfaces/external';
55-
import {
56-
FASTIFY_ROUTE_CONFIG_METADATA,
57-
FASTIFY_ROUTE_CONSTRAINTS_METADATA,
58-
} from '../constants';
5959

6060
type FastifyHttp2SecureOptions<
6161
Server extends http2.Http2SecureServer,
@@ -554,14 +554,18 @@ export class FastifyAdapter<
554554
await this.registerMiddie();
555555
}
556556
return (path: string, callback: Function) => {
557+
const hasEndOfStringCharacter = path.endsWith('$');
558+
path = hasEndOfStringCharacter ? path.slice(0, -1) : path;
559+
557560
let normalizedPath = path.endsWith('/*')
558561
? `${path.slice(0, -1)}(.*)`
559562
: path;
560563

561564
// Fallback to "(.*)" to support plugins like GraphQL
562565
normalizedPath = normalizedPath === '/(.*)' ? '(.*)' : normalizedPath;
563566

564-
const re = pathToRegexp(normalizedPath);
567+
let re = pathToRegexp(normalizedPath);
568+
re = hasEndOfStringCharacter ? new RegExp(re.source + '$', re.flags) : re;
565569

566570
// The following type assertion is valid as we use import('@fastify/middie') rather than require('@fastify/middie')
567571
// ref https://github.com/fastify/middie/pull/55

0 commit comments

Comments
 (0)