My team and I are trying to mutate the response.end
method in our Express middleware in order to have extra functionality be called just before the server responds back to the client.
Here is our attempt:
return (req: Request, res: Response, next: NextFunction): NextFunction => {
// reassign res.end in order to allow logger functionality before
// a response is sent back the client
const temp = res.end;
res.end = () => {
// instantiates PostQuery object with passed in query data from limiter middleware
const postQuery = new PostQuery(gateURI, projectID, res.locals.graphqlGate);
// our logger middleware functionality
try {
await postQuery.post();
} catch (err) {
if (err) console.log(err);
}
// our temp variable holding node's res.end definition
return temp.call(this);
};
return next();
};
Our test server throws this error when we include this function in our middleware chain:
TypeError: Cannot read properties of undefined (reading 'finished')
at end (node:_http_outgoing:856:19)
at /Users/jon/Documents/Solo Projects/OSP/graphQL-gate-logger/src/index.ts:65:25
index.ts:65
points to return temp.call(this)
We have also tried return temp()
, as well as binding temp to the res object, and receive the same error in every instance.
Is there some other way we can reach this goal or do we have to start back at the drawing board?
CodePudding user response:
If you don't have to execute your code BEFORE the response has been sent, but can instead do it right afterwards, then you can use the finish
event on the res
stream.
app.use((req, res, next) => {
res.on('finish', () => {
console.log(`got finish event for ${req.url}`);
// do your business here after a response has been sent
});
next();
});
There are also a couple problems with your existing override middleware. First off, you aren't preserving arguments that can be optionally send to res.end()
. Second, res.end()
is supposed to return res
which makes it chainable. You aren't doing that. You have assigned it an async
function which returns a promise, not res
.
Though I think it would be much better to use the finish
event as illustrated above and not have to override any methods, this would fix some of the problems with your override:
return (req: Request, res: Response, next: NextFunction): NextFunction => {
// reassign res.end in order to allow logger functionality before
// a response is sent back the client
const origEnd = res.end;
res.end = function(...args) {
// instantiates PostQuery object with passed in query data from limiter middleware
const postQuery = new PostQuery(gateURI, projectID, res.locals.graphqlGate);
// our logger middleware functionality
postQuery.post().catch(err => {
console.log(err);
}).finally(() => {
return origEnd.call(this, ...args);
});
return res;
};
return next();
};