diff --git a/packages/event-handler/src/rest/Router.ts b/packages/event-handler/src/rest/Router.ts index 40699f804f..96d383ec20 100644 --- a/packages/event-handler/src/rest/Router.ts +++ b/packages/event-handler/src/rest/Router.ts @@ -308,19 +308,11 @@ class Router { ]); requestContext.params = route?.params ?? {}; - const middlewareResult = await middleware({ + await middleware({ reqCtx: requestContext, next: () => Promise.resolve(), }); - // middleware result takes precedence to allow short-circuiting - if (middlewareResult !== undefined) { - requestContext.res = handlerResultToWebResponse(middlewareResult, { - statusCode: getStatusCode(middlewareResult), - resHeaders: requestContext.res.headers, - }); - } - return requestContext; } catch (error) { this.logger.debug(`There was an error processing the request: ${error}`); diff --git a/packages/event-handler/src/rest/utils.ts b/packages/event-handler/src/rest/utils.ts index 780c61a065..18a8787221 100644 --- a/packages/event-handler/src/rest/utils.ts +++ b/packages/event-handler/src/rest/utils.ts @@ -33,6 +33,7 @@ import { SAFE_CHARS, UNSAFE_CHARS, } from './constants.js'; +import { handlerResultToWebResponse } from './converters.js'; export function getPathString(path: Path): string { return isString(path) ? path : path.source.replaceAll(/\\\//g, '/'); @@ -230,6 +231,11 @@ export const isExtendedAPIGatewayProxyResult = ( * follows the onion model where middleware executes in order before `next()` and in * reverse order after `next()`. * + * When a middleware returns a value(short-circuits), that result becomes the response + * and the `res` object in the `RequestContext` is mutated with that result converted + * to a Web Response preserving any existing headers while applying the status code + * from the middleware result. + * * @param middleware - Array of middleware functions to compose * @returns A single middleware function that executes all provided middleware in sequence * @@ -294,8 +300,13 @@ export const composeMiddleware = (middleware: Middleware[]): Middleware => { ); } + // middleware result takes precedence to allow short-circuiting if (middlewareResult !== undefined) { result = middlewareResult; + reqCtx.res = handlerResultToWebResponse(middlewareResult, { + statusCode: getStatusCode(middlewareResult), + resHeaders: reqCtx.res.headers, + }); } }; 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 1c5f9c8c96..fe37c7105e 100644 --- a/packages/event-handler/tests/unit/rest/Router/middleware.test.ts +++ b/packages/event-handler/tests/unit/rest/Router/middleware.test.ts @@ -777,5 +777,33 @@ describe('Class: Router - Middleware', () => { expect(result.statusCode).toBe(403); expect(result.body).toBe('Route middleware response'); }); + + it('allows post processing middleware to access the response returned early by a pre-processing middleware', async () => { + // Prepare + const app = new Router(); + let message = ''; + app.get( + '/test', + [ + async ({ reqCtx, next }) => { + await next(); + const clonedRes = reqCtx.res.clone(); + message = (await clonedRes.json()).message; + }, + () => { + return Promise.resolve({ message: 'Middleware applied' }); + }, + ], + () => { + return { message: 'Handler applied' }; + } + ); + + // Act + await app.resolve(createTestEvent('/test', 'GET'), context); + + // Assess + expect(message).toEqual('Middleware applied'); + }); }); });