Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): global prefix exclude when versioning is turned on #11650

Merged
merged 1 commit into from May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 66 additions & 0 deletions integration/versioning/e2e/uri-versioning.spec.ts
Expand Up @@ -352,4 +352,70 @@ describe('URI Versioning', () => {
await app.close();
});
});

// ======================================================================== //
describe('with the global prefix enabled and an excluded route', () => {
before(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();

app = moduleRef.createNestApplication();
app.setGlobalPrefix('api', { exclude: ['/foo/bar'] });
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
});
await app.init();
});

describe('GET /', () => {
it('V1', () => {
return request(app.getHttpServer())
.get('/api/v1')
.expect(200)
.expect('Hello World V1!');
});

it('V2', () => {
return request(app.getHttpServer())
.get('/api/v2')
.expect(200)
.expect('Hello World V2!');
});

it('V3', () => {
return request(app.getHttpServer()).get('/api/v3').expect(404);
});

it('No Version', () => {
return request(app.getHttpServer()).get('/api').expect(404);
});
});

describe('GET /foo/bar (excluded from the API prefix)', () => {
it('V1', () => {
return request(app.getHttpServer())
.get('/v1/foo/bar')
.expect(200)
.expect('Hello FooBar!');
});

it('V2', () => {
return request(app.getHttpServer()).get('/v2/foo/bar').expect(404);
});

it('V3', () => {
return request(app.getHttpServer()).get('/v3/foo/bar').expect(404);
});

it('No Version', () => {
return request(app.getHttpServer()).get('/foo/bar').expect(404);
});
});

after(async () => {
await app.close();
});
});
});
53 changes: 50 additions & 3 deletions packages/core/router/route-path-factory.ts
@@ -1,10 +1,11 @@
import {
flatten,
RequestMethod,
VERSION_NEUTRAL,
VersioningOptions,
VersioningType,
VERSION_NEUTRAL,
flatten,
} from '@nestjs/common';
import { VersionValue } from '@nestjs/common/interfaces';
import {
addLeadingSlash,
isUndefined,
Expand Down Expand Up @@ -57,7 +58,14 @@ export class RoutePathFactory {

if (metadata.globalPrefix) {
paths = paths.map(path => {
if (this.isExcludedFromGlobalPrefix(path, requestMethod)) {
if (
this.isExcludedFromGlobalPrefix(
path,
requestMethod,
versionOrVersions,
metadata.versioningOptions,
)
) {
return path;
}
return stripEndSlash(metadata.globalPrefix || '') + path;
Expand Down Expand Up @@ -109,15 +117,54 @@ export class RoutePathFactory {
public isExcludedFromGlobalPrefix(
path: string,
requestMethod?: RequestMethod,
versionOrVersions?: VersionValue,
versioningOptions?: VersioningOptions,
) {
if (isUndefined(requestMethod)) {
return false;
}
const options = this.applicationConfig.getGlobalPrefixOptions();
const excludedRoutes = options.exclude;

if (
versionOrVersions &&
versionOrVersions !== VERSION_NEUTRAL &&
versioningOptions?.type === VersioningType.URI
) {
path = this.truncateVersionPrefixFromPath(
path,
versionOrVersions,
versioningOptions,
);
}
return (
Array.isArray(excludedRoutes) &&
isRouteExcluded(excludedRoutes, path, requestMethod)
);
}

private truncateVersionPrefixFromPath(
path: string,
versionValue: Exclude<VersionValue, typeof VERSION_NEUTRAL>,
versioningOptions: VersioningOptions,
) {
if (typeof versionValue !== 'string') {
versionValue.forEach(version => {
if (typeof version === 'string') {
path = this.truncateVersionPrefixFromPath(
path,
version,
versioningOptions,
);
}
});
return path;
}

const prefix = `/${this.getVersionPrefix(
versioningOptions,
)}${versionValue}`;

return path.startsWith(prefix) ? path.replace(prefix, '') : path;
}
}