diff --git a/packages/event-handler/src/rest/Router.ts b/packages/event-handler/src/rest/Router.ts index 0dfeeecadf..03bb209523 100644 --- a/packages/event-handler/src/rest/Router.ts +++ b/packages/event-handler/src/rest/Router.ts @@ -164,9 +164,9 @@ class Router { * * @example * ```typescript - * const authMiddleware: Middleware = async (params, reqCtx, next) => { + * const authMiddleware: Middleware = async ({ params, reqCtx, next }) => { * // Authentication logic - * if (!isAuthenticated(reqCtx.request)) { + * if (!isAuthenticated(reqCtx.req)) { * return new Response('Unauthorized', { status: 401 }); * } * await next(); @@ -215,23 +215,27 @@ class Router { }; } - const request = proxyEventToWebRequest(event); + const req = proxyEventToWebRequest(event); const requestContext: RequestContext = { event, context, - request, + req, // this response should be overwritten by the handler, if it isn't // it means something went wrong with the middleware chain res: new Response('', { status: 500 }), }; try { - const path = new URL(request.url).pathname as Path; + const path = new URL(req.url).pathname as Path; const route = this.routeRegistry.resolve(method, path); - const handlerMiddleware: Middleware = async (params, reqCtx, next) => { + const handlerMiddleware: Middleware = async ({ + params, + reqCtx, + next, + }) => { if (route === null) { const notFoundRes = await this.handleError( new NotFoundError(`Route ${path} for method ${method} not found`), @@ -263,11 +267,11 @@ class Router { handlerMiddleware, ]); - const middlewareResult = await middleware( - route?.params ?? {}, - requestContext, - () => Promise.resolve() - ); + const middlewareResult = await middleware({ + params: route?.params ?? {}, + reqCtx: requestContext, + next: () => Promise.resolve(), + }); // middleware result takes precedence to allow short-circuiting const result = middlewareResult ?? requestContext.res; diff --git a/packages/event-handler/src/rest/middleware/compress.ts b/packages/event-handler/src/rest/middleware/compress.ts index 70bffebd30..bb11c02685 100644 --- a/packages/event-handler/src/rest/middleware/compress.ts +++ b/packages/event-handler/src/rest/middleware/compress.ts @@ -67,12 +67,10 @@ const compress = (options?: CompressionOptions): Middleware => { const threshold = options?.threshold ?? DEFAULT_COMPRESSION_RESPONSE_THRESHOLD; - return async (_, reqCtx, next) => { + return async ({ reqCtx, next }) => { await next(); - if ( - !shouldCompress(reqCtx.request, reqCtx.res, preferredEncoding, threshold) - ) { + if (!shouldCompress(reqCtx.req, reqCtx.res, preferredEncoding, threshold)) { return; } diff --git a/packages/event-handler/src/rest/middleware/cors.ts b/packages/event-handler/src/rest/middleware/cors.ts index 983f805530..a1ac697bfb 100644 --- a/packages/event-handler/src/rest/middleware/cors.ts +++ b/packages/event-handler/src/rest/middleware/cors.ts @@ -96,16 +96,16 @@ export const cors = (options?: CorsOptions): Middleware => { } }; - return async (_params, reqCtx, next) => { - const requestOrigin = reqCtx.request.headers.get('Origin'); + return async ({ reqCtx, next }) => { + const requestOrigin = reqCtx.req.headers.get('Origin'); if (!isOriginAllowed(requestOrigin)) { await next(); return; } // Handle preflight OPTIONS request - if (reqCtx.request.method === HttpVerbs.OPTIONS) { - if (!isValidPreflightRequest(reqCtx.request.headers)) { + if (reqCtx.req.method === HttpVerbs.OPTIONS) { + if (!isValidPreflightRequest(reqCtx.req.headers)) { await next(); return; } diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index 1fb3d5df96..792b85854b 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -6,7 +6,6 @@ import type { HttpMethod, Middleware, Path, - RequestContext, ValidationResult, } from '../types/rest.js'; import { @@ -129,13 +128,13 @@ export const isAPIGatewayProxyResult = ( * * @example * ```typescript - * const middleware1: Middleware = async (params, options, next) => { + * const middleware1: Middleware = async ({params, options, next}) => { * console.log('middleware1 start'); * await next(); * console.log('middleware1 end'); * }; * - * const middleware2: Middleware = async (params, options, next) => { + * const middleware2: Middleware = async ({params, options, next}) => { * console.log('middleware2 start'); * await next(); * console.log('middleware2 end'); @@ -151,11 +150,7 @@ export const isAPIGatewayProxyResult = ( * ``` */ export const composeMiddleware = (middleware: Middleware[]): Middleware => { - return async ( - params: Record, - reqCtx: RequestContext, - next: () => Promise - ): Promise => { + return async ({ params, reqCtx, next }): Promise => { let index = -1; let result: HandlerResponse | undefined; @@ -181,7 +176,11 @@ export const composeMiddleware = (middleware: Middleware[]): Middleware => { return result; }; - const middlewareResult = await middlewareFn(params, reqCtx, nextFn); + const middlewareResult = await middlewareFn({ + params, + reqCtx, + next: nextFn, + }); if (nextPromise && !nextAwaited && i < middleware.length - 1) { throw new Error( diff --git a/packages/event-handler/src/types/rest.ts b/packages/event-handler/src/types/rest.ts index 0b660330bd..d59b174a80 100644 --- a/packages/event-handler/src/types/rest.ts +++ b/packages/event-handler/src/types/rest.ts @@ -15,7 +15,7 @@ type ErrorResponse = { }; type RequestContext = { - request: Request; + req: Request; event: APIGatewayProxyEvent; context: Context; res: Response; @@ -86,11 +86,11 @@ type RestRouteOptions = { type NextFunction = () => Promise; -type Middleware = ( - params: Record, - reqCtx: RequestContext, - next: NextFunction -) => Promise; +type Middleware = (args: { + params: Record; + reqCtx: RequestContext; + next: NextFunction; +}) => Promise; type RouteRegistryOptions = { /** 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 b983b4ed2b..f2be005e58 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 @@ -91,7 +91,7 @@ describe('Class: Router - Basic Routing', () => { app.get('/test', async (_params, reqCtx) => { return { - hasRequest: reqCtx.request instanceof Request, + hasRequest: reqCtx.req instanceof Request, hasEvent: reqCtx.event === testEvent, hasContext: reqCtx.context === context, }; diff --git a/packages/event-handler/tests/unit/rest/Router/decorators.test.ts b/packages/event-handler/tests/unit/rest/Router/decorators.test.ts index 07cae4b0f2..3510516bc0 100644 --- a/packages/event-handler/tests/unit/rest/Router/decorators.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/decorators.test.ts @@ -400,7 +400,7 @@ describe('Class: Router - Decorators', () => { @app.get('/test') public async getTest(_params: any, reqCtx: any) { return { - hasRequest: reqCtx.request instanceof Request, + hasRequest: reqCtx.req instanceof Request, hasEvent: reqCtx.event === testEvent, hasContext: reqCtx.context === context, }; @@ -435,7 +435,7 @@ describe('Class: Router - Decorators', () => { statusCode: HttpErrorCodes.BAD_REQUEST, error: 'Bad Request', message: error.message, - hasRequest: reqCtx.request instanceof Request, + hasRequest: reqCtx.req instanceof Request, hasEvent: reqCtx.event === testEvent, hasContext: reqCtx.context === context, }; diff --git a/packages/event-handler/tests/unit/rest/Router/error-handling.test.ts b/packages/event-handler/tests/unit/rest/Router/error-handling.test.ts index bd6c924039..d18778bcb0 100644 --- a/packages/event-handler/tests/unit/rest/Router/error-handling.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/error-handling.test.ts @@ -375,7 +375,7 @@ describe('Class: Router - Error Handling', () => { statusCode: HttpErrorCodes.BAD_REQUEST, error: 'Bad Request', message: error.message, - hasRequest: reqCtx.request instanceof Request, + hasRequest: reqCtx.req instanceof Request, hasEvent: reqCtx.event === testEvent, hasContext: reqCtx.context === context, })); diff --git a/packages/event-handler/tests/unit/rest/Router/middleware.test.ts b/packages/event-handler/tests/unit/rest/Router/middleware.test.ts index 9561e1eb18..c87d247aa9 100644 --- a/packages/event-handler/tests/unit/rest/Router/middleware.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/middleware.test.ts @@ -44,16 +44,17 @@ describe('Class: Router - Middleware', () => { const app = new Router(); const executionOrder: string[] = []; - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { executionOrder.push('global-middleware'); await next(); }); const middleware: Middleware[] = middlewareNames.map( - (name) => async (_params, _reqCtx, next) => { - executionOrder.push(name); - await next(); - } + (name) => + async ({ next }) => { + executionOrder.push(name); + await next(); + } ); app.get(path as Path, middleware, async () => { @@ -137,7 +138,7 @@ describe('Class: Router - Middleware', () => { let middlewareParams: Record | undefined; let middlewareOptions: RequestContext | undefined; - app.use(async (params, reqCtx, next) => { + app.use(async ({ params, reqCtx, next }) => { middlewareParams = params; middlewareOptions = reqCtx; await next(); @@ -153,7 +154,7 @@ describe('Class: Router - Middleware', () => { expect(middlewareParams).toEqual({ id: '123' }); expect(middlewareOptions?.event).toBe(testEvent); expect(middlewareOptions?.context).toBe(context); - expect(middlewareOptions?.request).toBeInstanceOf(Request); + expect(middlewareOptions?.req).toBeInstanceOf(Request); }); it('returns error response when next() is called multiple times', async () => { @@ -161,7 +162,7 @@ describe('Class: Router - Middleware', () => { vi.stubEnv('POWERTOOLS_DEV', 'true'); const app = new Router(); - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { await next(); await next(); }); @@ -185,11 +186,11 @@ describe('Class: Router - Middleware', () => { vi.stubEnv('POWERTOOLS_DEV', 'true'); const app = new Router(); - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { await next(); }); - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { next(); }); @@ -241,7 +242,7 @@ describe('Class: Router - Middleware', () => { const app = new Router(); const executionOrder: string[] = []; - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { executionOrder.push('middleware1-start'); await next(); executionOrder.push('middleware1-end'); @@ -362,7 +363,7 @@ describe('Class: Router - Middleware', () => { // Prepare const app = new Router(); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { await next(); reqCtx.res.headers.set('x-custom-header', 'middleware-value'); reqCtx.res.headers.set('x-request-id', '12345'); @@ -393,7 +394,7 @@ describe('Class: Router - Middleware', () => { // Prepare const app = new Router(); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { await next(); const originalBody = await reqCtx.res.text(); reqCtx.res = new Response(`Modified: ${originalBody}`, { @@ -422,7 +423,7 @@ describe('Class: Router - Middleware', () => { // Prepare const app = new Router(); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { reqCtx.res.headers.set('x-before-handler', 'middleware-value'); await next(); }); @@ -451,7 +452,7 @@ describe('Class: Router - Middleware', () => { // Prepare const app = new Router(); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { reqCtx.res.headers.set('x-before-handler', 'middleware-value'); await next(); }); @@ -478,12 +479,12 @@ describe('Class: Router - Middleware', () => { // Prepare const app = new Router(); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { reqCtx.res.headers.set('x-test-header', 'before-next'); await next(); }); - app.use(async (_params, reqCtx, next) => { + app.use(async ({ reqCtx, next }) => { await next(); reqCtx.res.headers.set('x-test-header', 'after-next'); }); @@ -531,7 +532,7 @@ describe('Class: Router - Middleware', () => { const app = new Router(); const executionOrder: string[] = []; - app.use(async (_params, _reqCtx, next) => { + app.use(async ({ next }) => { executionOrder.push('middleware-start'); await next(); executionOrder.push('middleware-end'); diff --git a/packages/event-handler/tests/unit/rest/helpers.ts b/packages/event-handler/tests/unit/rest/helpers.ts index 6edd2c4678..960fe2c437 100644 --- a/packages/event-handler/tests/unit/rest/helpers.ts +++ b/packages/event-handler/tests/unit/rest/helpers.ts @@ -28,7 +28,7 @@ export const createTrackingMiddleware = ( name: string, executionOrder: string[] ): Middleware => { - return async (_params, _options, next) => { + return async ({ next }) => { executionOrder.push(`${name}-start`); await next(); executionOrder.push(`${name}-end`); @@ -40,7 +40,7 @@ export const createThrowingMiddleware = ( executionOrder: string[], errorMessage: string ): Middleware => { - return async (_params, _options, _next) => { + return async () => { executionOrder.push(name); throw new Error(errorMessage); }; @@ -51,7 +51,7 @@ export const createReturningMiddleware = ( executionOrder: string[], response: any ): Middleware => { - return async (_params, _options, _next) => { + return async () => { executionOrder.push(name); return response; }; @@ -61,7 +61,7 @@ export const createNoNextMiddleware = ( name: string, executionOrder: string[] ): Middleware => { - return async (_params, _options, _next) => { + return async () => { executionOrder.push(name); // Intentionally doesn't call next() }; @@ -70,10 +70,10 @@ export const createNoNextMiddleware = ( export const createSettingHeadersMiddleware = (headers: { [key: string]: string; }): Middleware => { - return async (_params, options, next) => { + return async ({ reqCtx, next }) => { await next(); Object.entries(headers).forEach(([key, value]) => { - options.res.headers.set(key, value); + reqCtx.res.headers.set(key, value); }); }; }; @@ -81,10 +81,10 @@ export const createSettingHeadersMiddleware = (headers: { export const createHeaderCheckMiddleware = (headers: { [key: string]: string; }): Middleware => { - return async (_params, options, next) => { - options.res.headers.forEach((value, key) => { + return async ({ reqCtx, next }) => { + reqCtx.res.headers.forEach((value, key) => { headers[key] = value; }); await next(); }; -}; \ No newline at end of file +}; diff --git a/packages/event-handler/tests/unit/rest/utils.test.ts b/packages/event-handler/tests/unit/rest/utils.test.ts index 7a85d700af..db8308cd63 100644 --- a/packages/event-handler/tests/unit/rest/utils.test.ts +++ b/packages/event-handler/tests/unit/rest/utils.test.ts @@ -449,12 +449,12 @@ describe('Path Utilities', () => { it('executes middleware in order', async () => { const executionOrder: string[] = []; const middleware: Middleware[] = [ - async (_params, _reqCtx, next) => { + async ({ next }) => { executionOrder.push('middleware1-start'); await next(); executionOrder.push('middleware1-end'); }, - async (_params, _reqCtx, next) => { + async ({ next }) => { executionOrder.push('middleware2-start'); await next(); executionOrder.push('middleware2-end'); @@ -462,8 +462,12 @@ describe('Path Utilities', () => { ]; const composed = composeMiddleware(middleware); - await composed({}, mockOptions, async () => { - executionOrder.push('handler'); + await composed({ + params: {}, + reqCtx: mockOptions, + next: async () => { + executionOrder.push('handler'); + }, }); expect(executionOrder).toEqual([ @@ -477,17 +481,21 @@ describe('Path Utilities', () => { it('returns result from middleware that short-circuits', async () => { const middleware: Middleware[] = [ - async (_params, _reqCtx, next) => { + async ({ next }) => { await next(); }, - async (_params, _reqCtx, _next) => { + async () => { return { shortCircuit: true }; }, ]; const composed = composeMiddleware(middleware); - const result = await composed({}, mockOptions, async () => { - return { handler: true }; + const result = await composed({ + params: {}, + reqCtx: mockOptions, + next: async () => { + return { handler: true }; + }, }); expect(result).toEqual({ shortCircuit: true }); @@ -495,14 +503,18 @@ describe('Path Utilities', () => { it('returns result from next function when middleware does not return', async () => { const middleware: Middleware[] = [ - async (_params, _reqCtx, next) => { + async ({ next }) => { await next(); }, ]; const composed = composeMiddleware(middleware); - const result = await composed({}, mockOptions, async () => { - return { handler: true }; + const result = await composed({ + params: {}, + reqCtx: mockOptions, + next: async () => { + return { handler: true }; + }, }); expect(result).toEqual({ handler: true }); @@ -510,7 +522,7 @@ describe('Path Utilities', () => { it('throws error when next() is called multiple times', async () => { const middleware: Middleware[] = [ - async (_params, _reqCtx, next) => { + async ({ next }) => { await next(); await next(); }, @@ -518,15 +530,19 @@ describe('Path Utilities', () => { const composed = composeMiddleware(middleware); - await expect(composed({}, mockOptions, async () => {})).rejects.toThrow( - 'next() called multiple times' - ); + await expect( + composed({ params: {}, reqCtx: mockOptions, next: async () => {} }) + ).rejects.toThrow('next() called multiple times'); }); it('handles empty middleware array', async () => { const composed = composeMiddleware([]); - const result = await composed({}, mockOptions, async () => { - return { handler: true }; + const result = await composed({ + params: {}, + reqCtx: mockOptions, + next: async () => { + return { handler: true }; + }, }); expect(result).toEqual({ handler: true }); @@ -534,14 +550,18 @@ describe('Path Utilities', () => { it('returns undefined when next function returns undefined', async () => { const middleware: Middleware[] = [ - async (_params, _reqCtx, next) => { + async ({ next }) => { await next(); }, ]; const composed = composeMiddleware(middleware); - const result = await composed({}, mockOptions, async () => { - return undefined; + const result = await composed({ + params: {}, + reqCtx: mockOptions, + next: async () => { + return undefined; + }, }); expect(result).toBeUndefined();