From 4b404595abed67b7a5b640ba5f93f185abebc7b3 Mon Sep 17 00:00:00 2001 From: Yan Date: Thu, 16 Oct 2025 19:34:47 -0700 Subject: [PATCH 1/2] fix: merge req.body modifications into decoded request Added test case to verify that middleware modifications to the req object persist through the middleware chain. This addresses the issue where normal Express middleware behavior wasn't being tested with a realistic use case. --- packages/express-wrapper/src/middleware.ts | 2 +- .../express-wrapper/test/middleware.test.ts | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/express-wrapper/src/middleware.ts b/packages/express-wrapper/src/middleware.ts index 947760f7..38fd12e3 100644 --- a/packages/express-wrapper/src/middleware.ts +++ b/packages/express-wrapper/src/middleware.ts @@ -216,5 +216,5 @@ export async function runMiddlewareChainIgnoringResults< } }); } - return input; + return { ...input, ...(req.body || {}) }; } diff --git a/packages/express-wrapper/test/middleware.test.ts b/packages/express-wrapper/test/middleware.test.ts index 397f4e03..938b3938 100644 --- a/packages/express-wrapper/test/middleware.test.ts +++ b/packages/express-wrapper/test/middleware.test.ts @@ -40,6 +40,38 @@ test('should handle errors passed to next()', async () => { ); }); +test('middleware that modifies req should pass changes through chain', async () => { + const testReq = { body: {}, headers: {} } as express.Request; + const testRes = {} as express.Response; + + const modifyReqMiddleware: express.RequestHandler = (req, _res, next) => { + (req as any).userId = 123; + next(); + }; + + const checkReqMiddleware: express.RequestHandler = (req, _res, next) => { + assert.equal( + (req as any).userId, + 123, + 'userId should still be on req in second middleware', + ); + next(); + }; + + await runMiddlewareChain( + { foo: 'test' }, + [modifyReqMiddleware, noopMiddleware, checkReqMiddleware], + testReq, + testRes, + ); + + assert.equal( + (testReq as any).userId, + 123, + 'req should still have userId after chain', + ); +}); + test('should work with middleware that return values', async () => { const result = await runMiddlewareChain( { foo: 'test' }, From b3c6bb13b4b5d05e8dabb1d52b36daf91a06309b Mon Sep 17 00:00:00 2001 From: Yan Date: Fri, 17 Oct 2025 13:15:11 -0700 Subject: [PATCH 2/2] test: verify route-level middleware req.body modifications reach handler --- packages/express-wrapper/test/server.test.ts | 56 ++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packages/express-wrapper/test/server.test.ts b/packages/express-wrapper/test/server.test.ts index 03461f2e..5dd06366 100644 --- a/packages/express-wrapper/test/server.test.ts +++ b/packages/express-wrapper/test/server.test.ts @@ -276,3 +276,59 @@ test('should return a 400 when request fails to decode', async () => { assert(response.body.error.startsWith('Invalid value undefined supplied to')); }); + +test('middleware that modifies req.body should reach handler even without routeHandler()', async () => { + const PostWithData = httpRoute({ + path: '/data', + method: 'POST', + request: httpRequest({ + body: { + originalField: t.string, + addedByMiddleware: optional(t.string), + }, + }), + response: { + 200: t.type({ + originalField: t.string, + addedByMiddleware: optional(t.string), + }), + }, + }); + + const testApiSpec = apiSpec({ + 'test.route': { + post: PostWithData, + }, + }); + + const modifyBodyMiddleware: express.RequestHandler = (req, _res, next) => { + req.body.addedByMiddleware = 'ADDED'; + next(); + }; + + const handler = async (params: { originalField: string; addedByMiddleware?: string }) => { + return { + type: 200, + payload: { + originalField: params.originalField, + addedByMiddleware: params.addedByMiddleware, + }, + } as const; + }; + + const app = createServer(testApiSpec, (app: express.Application) => { + app.use(express.json()); + return { + 'test.route': { + post: { middleware: [modifyBodyMiddleware], handler }, + }, + }; + }); + + const response = await supertest(app) + .post('/data') + .send({ originalField: 'test' }) + .expect(200); + + assert.equal(response.body.addedByMiddleware, 'ADDED', 'addedByMiddleware should be present because req.body is part of req.decoded'); +});