Skip to content

Commit

Permalink
feat(core): middleware runs once for matching route
Browse files Browse the repository at this point in the history
  • Loading branch information
rychardvale committed Jun 20, 2022
1 parent 83098e2 commit 9f50226
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 1 deletion.
103 changes: 103 additions & 0 deletions integration/hello-world/e2e/middleware-run-match-route.ts
@@ -0,0 +1,103 @@
import {
Controller,
Get,
INestApplication,
Injectable,
MiddlewareConsumer,
NestMiddleware,
Module,
} from '@nestjs/common';
import { Test } from '../../../packages/testing';
import * as request from 'supertest';
import { expect } from 'chai';

/**
* Number of times that the middleware was executed.
*/
let triggerCounter = 0;
@Injectable()
class Middleware implements NestMiddleware {
use(req, res, next) {
triggerCounter++;
next();
}
}

@Controller()
class TestController {
@Get('/test')
testA() {}

@Get('/:id')
testB() {}

@Get('/:id/test')
testC() {}

@Get('/:id/:nested')
testD() {}
}

@Module({
controllers: [TestController],
})
class TestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(Middleware).forRoutes(TestController);
}
}

describe('Middleware (run on route match)', () => {
let app: INestApplication;

beforeEach(async () => {
triggerCounter = 0;
app = (
await Test.createTestingModule({
imports: [TestModule],
}).compile()
).createNestApplication();

await app.init();
});

it(`forRoutes(TestController) should execute middleware once when request url is equal match`, () => {
return request(app.getHttpServer())
.get('/test')
.expect(200)
.then(() => {
expect(triggerCounter).to.be.eq(1);
});
});

it(`forRoutes(TestController) should execute middleware once when request url is not equal match`, () => {
return request(app.getHttpServer())
.get('/1')
.expect(200)
.then(() => {
expect(triggerCounter).to.be.eq(1);
});
});

it(`forRoutes(TestController) should execute middleware once when request url is not of nested params`, () => {
return request(app.getHttpServer())
.get('/1/test')
.expect(200)
.then(() => {
expect(triggerCounter).to.be.eq(1);
});
});

it(`forRoutes(TestController) should execute middleware once when request url is of nested params`, () => {
return request(app.getHttpServer())
.get('/1/abc')
.expect(200)
.then(() => {
expect(triggerCounter).to.be.eq(1);
});
});

afterEach(async () => {
await app.close();
});
});
23 changes: 22 additions & 1 deletion packages/core/middleware/builder.ts
Expand Up @@ -59,7 +59,8 @@ export class MiddlewareBuilder implements MiddlewareConsumer {
): MiddlewareConsumer {
const { middlewareCollection } = this.builder;

const forRoutes = this.getRoutesFlatList(routes);
const flattedRoutes = this.getRoutesFlatList(routes);
const forRoutes = this.removeOverlappedRoutes(flattedRoutes);
const configuration = {
middleware: filterMiddleware(
this.middleware,
Expand All @@ -82,5 +83,25 @@ export class MiddlewareBuilder implements MiddlewareConsumer {
.flatten()
.toArray();
}

private removeOverlappedRoutes(routes: RouteInfo[]) {
const regexMatchParams = /(:[^\/]*)/g;
const wildcard = '([^/]*)';
const routesWithRegex = routes
.filter(route => route.path.indexOf(':') >= 0)
.map(route => ({
path: route.path,
regex: new RegExp(
'^(' + route.path.replace(regexMatchParams, wildcard) + ')$',
'g',
),
}));
return routes.filter(route => {
const routeMatch = routesWithRegex.find(
v => route.path !== v.path && route.path.match(v.regex),
);
if (routeMatch === undefined) return route;
});
}
};
}

0 comments on commit 9f50226

Please sign in to comment.