Skip to content

Commit 2c3ae46

Browse files
committed
feat(controller): add version prefix handling for and controller and method-level overrides
1 parent 388cc0a commit 2c3ae46

2 files changed

Lines changed: 14 additions & 6 deletions

File tree

src/utils/decorators.utils.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ export function registerControllers(router: Router, controllers: any[]) {
12311231

12321232
// Use DI container to resolve controller (constructor injection + property injection)
12331233
const instance = diContainer.get(ControllerClass);
1234-
const basePath: string = Reflect.getMetadata('basePath', ControllerClass as object) || '';
1234+
let basePath: string = Reflect.getMetadata('basePath', ControllerClass as object) || '';
12351235
const routes: RouteDefinition[] = Reflect.getMetadata(ROUTES_KEY, ControllerClass as object) || [];
12361236

12371237
// Get controller-level decorators (fallback values)
@@ -1248,6 +1248,11 @@ export function registerControllers(router: Router, controllers: any[]) {
12481248
const controllerAfterHooks: Function[] = Reflect.getMetadata(AFTER_KEY, ControllerClass as object) || [];
12491249
const controllerContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass as object);
12501250

1251+
// Apply controller-level version prefix to base path
1252+
if (controllerVersion?.options?.addPrefix) {
1253+
basePath = `/${controllerVersion.version}${basePath || ''}`;
1254+
}
1255+
12511256
routes.forEach(({ path, method, handlerName }) => {
12521257
const methodMiddlewares: RequestHandler[] =
12531258
Reflect.getMetadata(MIDDLEWARE_KEY, instance as object, handlerName) || [];
@@ -1289,9 +1294,11 @@ export function registerControllers(router: Router, controllers: any[]) {
12891294
const rateLimitOptions:
12901295
| { max: number; windowMs: number; standardHeaders: boolean; legacyHeaders: boolean }
12911296
| undefined = Reflect.getMetadata(RATE_LIMIT_KEY, instance as object, handlerName) || controllerRateLimit;
1292-
const version:
1297+
const methodVersion:
12931298
| { version: string; options: { addPrefix: boolean; addHeader: boolean; headerName: string } }
1294-
| undefined = Reflect.getMetadata(VERSION_KEY, instance as object, handlerName) || controllerVersion;
1299+
| undefined = Reflect.getMetadata(VERSION_KEY, instance as object, handlerName);
1300+
// Method-level version overrides controller-level version
1301+
const version = methodVersion || controllerVersion;
12951302
const timeout: { ms: number } | undefined =
12961303
Reflect.getMetadata(TIMEOUT_KEY, instance as object, handlerName) || controllerTimeout;
12971304
const logConfig:
@@ -1315,8 +1322,9 @@ export function registerControllers(router: Router, controllers: any[]) {
13151322
}
13161323

13171324
let finalPath = path;
1318-
if (version?.options?.addPrefix) {
1319-
finalPath = `/${version.version}${path}`;
1325+
// Only apply method-level version prefix if it's different from controller-level
1326+
if (methodVersion?.options?.addPrefix && methodVersion.version !== controllerVersion?.version) {
1327+
finalPath = `/${methodVersion.version}${path}`;
13201328
}
13211329

13221330
const handler: RequestHandler = async (req, res, next) => {

tests/utils/decorator.utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ describe('Decorators and registerControllers', () => {
734734

735735
registerControllers(mockRouter, [OverrideController]);
736736
const [path, ...handlers] = mockRouter.get.mock.calls[0];
737-
expect(path).toBe('/override/v2/method-override');
737+
expect(path).toBe('/v1/override/v2/method-override');
738738

739739
const routeHandler = handlers[handlers.length - 1];
740740
await routeHandler(mockReq, mockRes, mockNext);

0 commit comments

Comments
 (0)