From fc32593f747dd967701bf3fb2afe33cb25a01616 Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Fri, 26 Sep 2025 19:16:12 +0100 Subject: [PATCH 01/10] Implemented catch all route using regex --- .../src/rest/RouteHandlerRegistry.ts | 61 ++++++++++++------- packages/event-handler/src/types/rest.ts | 2 +- .../unit/rest/Router/basic-routing.test.ts | 28 +++++++++ 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index 116b95b91e..990a0fad50 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -16,6 +16,7 @@ import { } from './utils.js'; class RouteHandlerRegistry { + readonly #regexRoutes: Map = new Map(); readonly #staticRoutes: Map = new Map(); readonly #dynamicRoutesSet: Set = new Set(); readonly #dynamicRoutes: DynamicRoute[] = []; @@ -103,6 +104,18 @@ class RouteHandlerRegistry { const compiled = compilePath(route.path); + if (/[^a-zA-Z0-9/-:]/.test(compiled.path)) { + if (this.#regexRoutes.has(route.id)) { + this.#logger.warn( + `Handler for method: ${route.method} and path: ${route.path} already exists. The previous handler will be replaced.` + ); + } + this.#regexRoutes.set(route.id, { + ...route, + ...compiled, + }); + return; + } if (compiled.isDynamic) { const dynamicRoute = { ...route, @@ -171,28 +184,10 @@ class RouteHandlerRegistry { }; } - for (const route of this.#dynamicRoutes) { - if (route.method !== method) continue; - - const match = route.regex.exec(path); - if (match?.groups) { - const params = match.groups; - - const processedParams = this.#processParams(params); - - const validation = this.#validateParams(processedParams); - - if (!validation.isValid) { - throw new ParameterValidationError(validation.issues); - } - - return { - handler: route.handler, - params: processedParams, - rawParams: params, - middleware: route.middleware, - }; - } + const routes = [...this.#dynamicRoutes, ...this.#regexRoutes.values()]; + for (const route of routes) { + const result = this.#processRoute(route, method, path); + if (result) return result; } return null; @@ -227,6 +222,28 @@ class RouteHandlerRegistry { ); } } + + #processRoute(route: DynamicRoute, method: HttpMethod, path: Path) { + if (route.method !== method) return; + + const match = route.regex.exec(path); + if (!match) return; + + const params = match.groups || {}; + const processedParams = this.#processParams(params); + const validation = this.#validateParams(processedParams); + + if (!validation.isValid) { + throw new ParameterValidationError(validation.issues); + } + + return { + handler: route.handler, + params: processedParams, + rawParams: params, + middleware: route.middleware, + }; + } } export { RouteHandlerRegistry }; diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index b7a0d2e21e..51316d7c7b 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -64,7 +64,7 @@ type HttpMethod = keyof typeof HttpVerbs; type HttpStatusCode = (typeof HttpStatusCodes)[keyof typeof HttpStatusCodes]; -type Path = `/${string}`; +type Path = string; type RestRouteHandlerOptions = { handler: RouteHandler; diff --git a/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts b/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts index a2de67e709..f5ae6178e9 100644 --- a/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts @@ -190,4 +190,32 @@ describe('Class: Router - Basic Routing', () => { 'Handler for method: GET and path: /todos already exists. The previous handler will be replaced.' ); }); + + it.each([ + ['/files/test', 'GET', 'serveFileOverride'], + ['/api/v1/test', 'GET', 'apiVersioning'], + ['/users/1/files/test', 'GET', 'dynamicRegex1'], + ['/any-route', 'GET', 'getAnyRoute'], + ['/no-matches', 'POST', 'catchAllUnmatched'], + ])('routes %s %s to %s handler', async (path, method, expectedApi) => { + // Prepare + const app = new Router(); + app.get('/files/.+', async () => ({ api: 'serveFile' })); + app.get('/files/.+', async () => ({ api: 'serveFileOverride' })); + app.get('/api/v\\d+/.*', async () => ({ api: 'apiVersioning' })); + app.get('/users/:userId/files/.+', async (reqCtx) => ({ + api: `dynamicRegex${reqCtx.params.userId}`, + })); + app.get('.+', async () => ({ api: 'getAnyRoute' })); + app.route(async () => ({ api: 'catchAllUnmatched' }), { + path: '.*', + method: [HttpVerbs.GET, HttpVerbs.POST], + }); + + // Act + const result = await app.resolve(createTestEvent(path, method), context); + + // Assess + expect(JSON.parse(result.body).api).toEqual(expectedApi); + }); }); From 3ba5d3a5fd64e8c37964b68d173c00fdda3bb582 Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Fri, 26 Sep 2025 19:43:10 +0100 Subject: [PATCH 02/10] Added regex routes in the merge function --- packages/event-handler/src/rest/RouteHandlerRegistry.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index 990a0fad50..c12baf1f10 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -210,6 +210,7 @@ class RouteHandlerRegistry { const routes = [ ...routeHandlerRegistry.#staticRoutes.values(), ...routeHandlerRegistry.#dynamicRoutes, + ...routeHandlerRegistry.#regexRoutes.values(), ]; for (const route of routes) { this.register( From 42c05f4b01745ae9e1a482155eaefc6b221f77bf Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Fri, 26 Sep 2025 20:13:47 +0100 Subject: [PATCH 03/10] Fixed prefixed routes without slash --- packages/event-handler/src/rest/utils.ts | 1 + packages/event-handler/src/types/rest.ts | 7 +++++-- packages/event-handler/tests/unit/rest/utils.test.ts | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index ca41f0a5a7..6207464d73 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -205,6 +205,7 @@ export const composeMiddleware = (middleware: Middleware[]): Middleware => { */ export const resolvePrefixedPath = (path: Path, prefix?: Path): Path => { if (prefix) { + if (!path.startsWith('/')) return `${prefix}/${path}`; return path === '/' ? prefix : `${prefix}${path}`; } return path; diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index 51316d7c7b..ebee7414df 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -80,13 +80,16 @@ type RestRouteOptions = { }; // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited -type NextFunction = () => Promise; +type NextFunction = () => + | Promise + | HandlerResponse + | void; type Middleware = (args: { reqCtx: RequestContext; next: NextFunction; // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited -}) => Promise; +}) => Promise | HandlerResponse | void; type RouteRegistryOptions = { /** diff --git a/packages/event-handler/tests/unit/rest/utils.test.ts b/packages/event-handler/tests/unit/rest/utils.test.ts index 927fae01eb..f56b20e736 100644 --- a/packages/event-handler/tests/unit/rest/utils.test.ts +++ b/packages/event-handler/tests/unit/rest/utils.test.ts @@ -577,6 +577,7 @@ describe('Path Utilities', () => { { path: '/test', prefix: '/prefix', expected: '/prefix/test' }, { path: '/', prefix: '/prefix', expected: '/prefix' }, { path: '/test', expected: '/test' }, + { path: '.+', prefix: '/prefix', expected: '/prefix/.+' }, ])('resolves prefixed path', ({ path, prefix, expected }) => { // Prepare & Act const resolvedPath = resolvePrefixedPath(path as Path, prefix as Path); From 838f77deab8635c2e67df398e6d7250f3f57448d Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Fri, 26 Sep 2025 20:32:31 +0100 Subject: [PATCH 04/10] simplified the regex --- packages/event-handler/src/rest/RouteHandlerRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index c12baf1f10..e45d674ddf 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -104,7 +104,7 @@ class RouteHandlerRegistry { const compiled = compilePath(route.path); - if (/[^a-zA-Z0-9/-:]/.test(compiled.path)) { + if (/[\w/:-]/.test(compiled.path)) { if (this.#regexRoutes.has(route.id)) { this.#logger.warn( `Handler for method: ${route.method} and path: ${route.path} already exists. The previous handler will be replaced.` From 857262e00c1793e03f544bc72831d59e3fc8a50e Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Fri, 26 Sep 2025 20:36:37 +0100 Subject: [PATCH 05/10] simplified the regex --- packages/event-handler/src/rest/RouteHandlerRegistry.ts | 2 +- packages/event-handler/src/types/rest.ts | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index e45d674ddf..047b05981b 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -104,7 +104,7 @@ class RouteHandlerRegistry { const compiled = compilePath(route.path); - if (/[\w/:-]/.test(compiled.path)) { + if (!/^[\w+/:-]+$/.test(compiled.path)) { if (this.#regexRoutes.has(route.id)) { this.#logger.warn( `Handler for method: ${route.method} and path: ${route.path} already exists. The previous handler will be replaced.` diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index ebee7414df..1f70aaf510 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -79,11 +79,9 @@ type RestRouteOptions = { middleware?: Middleware[]; }; -// biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited -type NextFunction = () => - | Promise - | HandlerResponse - | void; +type NextFunction = + () => // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited + Promise | HandlerResponse | void; type Middleware = (args: { reqCtx: RequestContext; From e8cba280180d28bead720b160719f547d718a92e Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Wed, 1 Oct 2025 00:03:22 +0100 Subject: [PATCH 06/10] Allowed RegExp in the Path --- packages/commons/src/index.ts | 1 + packages/commons/src/typeUtils.ts | 20 ++++++++ packages/commons/tests/unit/typeUtils.test.ts | 25 ++++++++++ .../src/rest/RouteHandlerRegistry.ts | 9 ++-- packages/event-handler/src/rest/utils.ts | 46 ++++++++++++++----- packages/event-handler/src/types/rest.ts | 9 ++-- .../unit/rest/Router/basic-routing.test.ts | 12 ++--- .../tests/unit/rest/utils.test.ts | 6 ++- 8 files changed, 100 insertions(+), 28 deletions(-) diff --git a/packages/commons/src/index.ts b/packages/commons/src/index.ts index aed1788618..17906e6e26 100644 --- a/packages/commons/src/index.ts +++ b/packages/commons/src/index.ts @@ -22,6 +22,7 @@ export { isNullOrUndefined, isNumber, isRecord, + isRegExp, isStrictEqual, isString, isStringUndefinedNullEmpty, diff --git a/packages/commons/src/typeUtils.ts b/packages/commons/src/typeUtils.ts index 2dca860b84..10cc93214f 100644 --- a/packages/commons/src/typeUtils.ts +++ b/packages/commons/src/typeUtils.ts @@ -176,6 +176,25 @@ const isStringUndefinedNullEmpty = (value: unknown) => { return false; }; +/** + * Check if a Regular Expression + * + * @example + * ```typescript + * import { isRegExp } from '@aws-lambda-powertools/commons/typeUtils'; + * + * const value = /^foo.+$/; + * if (isRegExp(value)) { + * // value is a Regular Expression + * } + * ``` + * + * @param value - The value to check + */ +const isRegExp = (value: unknown): value is RegExp => { + return value instanceof RegExp; +}; + /** * Get the type of a value as a string. * @@ -337,6 +356,7 @@ export { isNull, isNullOrUndefined, isStringUndefinedNullEmpty, + isRegExp, getType, isStrictEqual, }; diff --git a/packages/commons/tests/unit/typeUtils.test.ts b/packages/commons/tests/unit/typeUtils.test.ts index 99b281be87..72a719adf6 100644 --- a/packages/commons/tests/unit/typeUtils.test.ts +++ b/packages/commons/tests/unit/typeUtils.test.ts @@ -6,6 +6,7 @@ import { isNullOrUndefined, isNumber, isRecord, + isRegExp, isStrictEqual, isString, isStringUndefinedNullEmpty, @@ -224,6 +225,30 @@ describe('Functions: typeUtils', () => { }); }); + describe('Function: isRegExp', () => { + it('returns true when the passed value is a Regular Expression', () => { + // Prepare + const value = /^hello.+$/; + + // Act + const result = isRegExp(value); + + // Assess + expect(result).toBe(true); + }); + + it('returns false when the passed value is not a Regular Expression', () => { + // Prepare + const value = 123; + + // Act + const result = isRegExp(value); + + // Assess + expect(result).toBe(false); + }); + }); + describe('Function: getType', () => { it.each([ { diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index 047b05981b..c9e8686554 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -11,6 +11,7 @@ import { ParameterValidationError } from './errors.js'; import { Route } from './Route.js'; import { compilePath, + getPathString, resolvePrefixedPath, validatePathPattern, } from './utils.js'; @@ -45,8 +46,8 @@ class RouteHandlerRegistry { } // Routes with more path segments are more specific - const aSegments = a.path.split('/').length; - const bSegments = b.path.split('/').length; + const aSegments = getPathString(a.path).split('/').length; + const bSegments = getPathString(b.path).split('/').length; return bSegments - aSegments; } @@ -104,7 +105,7 @@ class RouteHandlerRegistry { const compiled = compilePath(route.path); - if (!/^[\w+/:-]+$/.test(compiled.path)) { + if (route.path instanceof RegExp) { if (this.#regexRoutes.has(route.id)) { this.#logger.warn( `Handler for method: ${route.method} and path: ${route.path} already exists. The previous handler will be replaced.` @@ -227,7 +228,7 @@ class RouteHandlerRegistry { #processRoute(route: DynamicRoute, method: HttpMethod, path: Path) { if (route.method !== method) return; - const match = route.regex.exec(path); + const match = route.regex.exec(getPathString(path)); if (!match) return; const params = match.groups || {}; diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index 6207464d73..53b204cde4 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -1,4 +1,8 @@ -import { isRecord, isString } from '@aws-lambda-powertools/commons/typeutils'; +import { + isRecord, + isRegExp, + isString, +} from '@aws-lambda-powertools/commons/typeutils'; import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; import type { CompiledRoute, @@ -15,13 +19,21 @@ import { UNSAFE_CHARS, } from './constants.js'; +export function getPathString(path: Path): string { + return isString(path) ? path : path.source.replace(/\\\//g, '/'); +} + export function compilePath(path: Path): CompiledRoute { const paramNames: string[] = []; - const regexPattern = path.replace(PARAM_PATTERN, (_match, paramName) => { - paramNames.push(paramName); - return `(?<${paramName}>[${SAFE_CHARS}${UNSAFE_CHARS}\\w]+)`; - }); + const pathString = getPathString(path); + const regexPattern = pathString.replace( + PARAM_PATTERN, + (_match, paramName) => { + paramNames.push(paramName); + return `(?<${paramName}>[${SAFE_CHARS}${UNSAFE_CHARS}\\w]+)`; + } + ); const finalPattern = `^${regexPattern}$`; @@ -36,9 +48,10 @@ export function compilePath(path: Path): CompiledRoute { export function validatePathPattern(path: Path): ValidationResult { const issues: string[] = []; - const matches = [...path.matchAll(PARAM_PATTERN)]; - if (path.includes(':')) { - const expectedParams = path.split(':').length; + const pathString = getPathString(path); + const matches = [...pathString.matchAll(PARAM_PATTERN)]; + if (pathString.includes(':')) { + const expectedParams = pathString.split(':').length; if (matches.length !== expectedParams - 1) { issues.push('Malformed parameter syntax. Use :paramName format.'); } @@ -200,13 +213,22 @@ export const composeMiddleware = (middleware: Middleware[]): Middleware => { /** * Resolves a prefixed path by combining the provided path and prefix. * + * The function returns a RegExp if any of the path or prefix is a RegExp. + * Otherwise, it returns a `/${string}` type value. + * * @param path - The path to resolve * @param prefix - The prefix to prepend to the path */ export const resolvePrefixedPath = (path: Path, prefix?: Path): Path => { - if (prefix) { - if (!path.startsWith('/')) return `${prefix}/${path}`; - return path === '/' ? prefix : `${prefix}${path}`; + if (!prefix) return path; + if (isRegExp(prefix)) { + if (isRegExp(path)) { + return new RegExp(`${getPathString(prefix)}/${getPathString(path)}`); + } + return new RegExp(`${getPathString(prefix)}${path}`); + } + if (isRegExp(path)) { + return new RegExp(`${prefix}/${getPathString(path)}`); } - return path; + return `${prefix}${path}`.replace(/\/$/, '') as Path; }; diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index 1f70aaf510..ca1875b4ef 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -64,7 +64,7 @@ type HttpMethod = keyof typeof HttpVerbs; type HttpStatusCode = (typeof HttpStatusCodes)[keyof typeof HttpStatusCodes]; -type Path = string; +type Path = `/${string}` | RegExp; type RestRouteHandlerOptions = { handler: RouteHandler; @@ -79,9 +79,10 @@ type RestRouteOptions = { middleware?: Middleware[]; }; -type NextFunction = - () => // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited - Promise | HandlerResponse | void; +type NextFunction = () => // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited + | Promise + | HandlerResponse + | void; type Middleware = (args: { reqCtx: RequestContext; diff --git a/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts b/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts index f5ae6178e9..3fdd5b0954 100644 --- a/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/basic-routing.test.ts @@ -200,15 +200,15 @@ describe('Class: Router - Basic Routing', () => { ])('routes %s %s to %s handler', async (path, method, expectedApi) => { // Prepare const app = new Router(); - app.get('/files/.+', async () => ({ api: 'serveFile' })); - app.get('/files/.+', async () => ({ api: 'serveFileOverride' })); - app.get('/api/v\\d+/.*', async () => ({ api: 'apiVersioning' })); - app.get('/users/:userId/files/.+', async (reqCtx) => ({ + app.get(/\/files\/.+/, async () => ({ api: 'serveFile' })); + app.get(/\/files\/.+/, async () => ({ api: 'serveFileOverride' })); + app.get(/\/api\/v\d+\/.*/, async () => ({ api: 'apiVersioning' })); + app.get(/\/users\/:userId\/files\/.+/, async (reqCtx) => ({ api: `dynamicRegex${reqCtx.params.userId}`, })); - app.get('.+', async () => ({ api: 'getAnyRoute' })); + app.get(/.+/, async () => ({ api: 'getAnyRoute' })); app.route(async () => ({ api: 'catchAllUnmatched' }), { - path: '.*', + path: /.*/, method: [HttpVerbs.GET, HttpVerbs.POST], }); diff --git a/packages/event-handler/tests/unit/rest/utils.test.ts b/packages/event-handler/tests/unit/rest/utils.test.ts index f56b20e736..95ea1af4a5 100644 --- a/packages/event-handler/tests/unit/rest/utils.test.ts +++ b/packages/event-handler/tests/unit/rest/utils.test.ts @@ -577,13 +577,15 @@ describe('Path Utilities', () => { { path: '/test', prefix: '/prefix', expected: '/prefix/test' }, { path: '/', prefix: '/prefix', expected: '/prefix' }, { path: '/test', expected: '/test' }, - { path: '.+', prefix: '/prefix', expected: '/prefix/.+' }, + { path: /.+/, prefix: '/prefix', expected: /\/prefix\/.+/ }, + { path: '/test', prefix: /\/prefix/, expected: /\/prefix\/test/ }, + { path: /.+/, prefix: /\/prefix/, expected: /\/prefix\/.+/ }, ])('resolves prefixed path', ({ path, prefix, expected }) => { // Prepare & Act const resolvedPath = resolvePrefixedPath(path as Path, prefix as Path); // Assert - expect(resolvedPath).toBe(expected); + expect(resolvedPath).toEqual(expected); }); }); }); From fed41925c6fe123f545a44c6a63f99785ff82074 Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Wed, 1 Oct 2025 00:20:47 +0100 Subject: [PATCH 07/10] Used replaceAll --- packages/event-handler/src/rest/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index 53b204cde4..a88b9dbe83 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -20,7 +20,7 @@ import { } from './constants.js'; export function getPathString(path: Path): string { - return isString(path) ? path : path.source.replace(/\\\//g, '/'); + return isString(path) ? path : path.source.replaceAll(/\\\//g, '/'); } export function compilePath(path: Path): CompiledRoute { From ddf1d2faabf9bdc33cb24f0eca68f45ca51a8aac Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Wed, 1 Oct 2025 10:34:57 +0100 Subject: [PATCH 08/10] Changed to use isRegExp --- packages/event-handler/src/rest/RouteHandlerRegistry.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/event-handler/src/rest/RouteHandlerRegistry.ts b/packages/event-handler/src/rest/RouteHandlerRegistry.ts index c9e8686554..c191d08398 100644 --- a/packages/event-handler/src/rest/RouteHandlerRegistry.ts +++ b/packages/event-handler/src/rest/RouteHandlerRegistry.ts @@ -1,4 +1,5 @@ import type { GenericLogger } from '@aws-lambda-powertools/commons/types'; +import { isRegExp } from '@aws-lambda-powertools/commons/typeutils'; import type { DynamicRoute, HttpMethod, @@ -105,7 +106,7 @@ class RouteHandlerRegistry { const compiled = compilePath(route.path); - if (route.path instanceof RegExp) { + if (isRegExp(route.path)) { if (this.#regexRoutes.has(route.id)) { this.#logger.warn( `Handler for method: ${route.method} and path: ${route.path} already exists. The previous handler will be replaced.` From 84090e79764c9e71c3eba75574d8f6da03abe52c Mon Sep 17 00:00:00 2001 From: Swopnil Dangol Date: Wed, 1 Oct 2025 10:44:16 +0100 Subject: [PATCH 09/10] Reverted the return type of the next function --- packages/event-handler/src/types/rest.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index ca1875b4ef..3fb4435507 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -79,16 +79,14 @@ type RestRouteOptions = { middleware?: Middleware[]; }; -type NextFunction = () => // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited - | Promise - | HandlerResponse - | void; +// biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited +type NextFunction = () => Promise; type Middleware = (args: { reqCtx: RequestContext; next: NextFunction; // biome-ignore lint/suspicious/noConfusingVoidType: To ensure next function is awaited -}) => Promise | HandlerResponse | void; +}) => Promise; type RouteRegistryOptions = { /** From 5cdb57e55e3ffddf6676f38b01aa033c58ae961a Mon Sep 17 00:00:00 2001 From: svozza Date: Fri, 3 Oct 2025 12:03:39 +0100 Subject: [PATCH 10/10] remove unused import --- packages/event-handler/src/rest/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index 1ce3134c7e..caf4ad82f8 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -4,7 +4,7 @@ import { isRegExp, isString, } from '@aws-lambda-powertools/commons/typeutils'; -import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; +import type { APIGatewayProxyEvent } from 'aws-lambda'; import type { CompiledRoute, ExtendedAPIGatewayProxyResult,