Request and Response Lifecyle in Node and Express - node.js

I have a very simple route setup for my web app,
router.get('/myTestRoute/:id', async (req: Request, res: Response, next: NextFunction) => {
await doSomeAsync(req, res);
res.json({ myObj: 32 });
return next();
}
The doSomeAsync actually performs a request to a service and takes up to 20 seconds. However the response that the user is looking for doesn't need or care about the doSomeAsync response, so I thought I could remove the await, so that it would look like this:
router.get('/myTestRoute/:id', async (req: Request, res: Response, next: NextFunction) => {
doSomeAsync(req, res);
res.json({ myObj: 32 });
return next();
}
Inside the doSomeAsync function, after the service call, we reference parameters on the req and res objects, like the parameters on the req object, and some authentication stuff on the res object.
I have found that this is not working, and I realized that I don't fully understand what happens with req and res after the response has been sent back to the user.
After I call res.json(), and then next(), what happens to the Request and Response objects, do they reset? Do they change in any way?
Should I refactor doSomeAsync() to accept the primitive values from req.params?

Related

Why does listening to an event make a more accurate response time measurement in Express.js?

I've written an Express.js middleware to measure an endpoint's response time that looks like this:
export function metricsMiddleware(req: Request, res: Response, next: NextFunction) {
const startTime = Date.now();
next();
const durationMillis = Date.now() - startTime;
console.log(durationMillis);
}
The values output are suspiciously low, in the range of sub-millisecond. I'm seeing an alternative approach to write it like:
export function metricsMiddleware(req: Request, res: Response, next: NextFunction) {
const startTime = Date.now();
res.on("finish", () => {
const durationMillis = Date.now() - startTime;
console.log(durationMillis);
})
next();
}
Why does the second approach work, while the first approach does not?
Because code executed by next() (which is whatever comes next after your middleware) may or may not be synchronous.
If everything after your middleware is synchronous (does not fetch anything from db etc) then it will be accurate.
But if you have anything asynchronous after the middleware then your console.log() will obviously execute befor next() is finished.

Add additional functionality to end method on Node/Express Response object?

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?
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();
};

Override default `Expect: 100-continue` behaviour in Firebase Functions

By default, requests sent to a Firebase Function with the Expect header set to 100-continue automatically reply with 100 Continue. We have a partner who sends requests with this header erroneously set, and replying with "100 Continue" is treated as a failure on their end. After the first request, our route handlers stop running (using Firebase emulator).
I tried the following:
app.on('checkContinue', ((req: any, res: any) => {
console.log('checkContinue');
return app(req, res);
}) as any);
app.on('checkExpectation', ((req: any, res: any) => {
console.log('checkExpectation');
return app(req, res);
}) as any);
I don't see anything in console logs (running Firebase Functions emulator).

How to use csurf middleware in tsoa express?

I am new to tsoa and I want to do CSRF implementation in my node app. I have been able to make api using app.use() but I want to write in tsoa. Is there any way?
In the pre-released version, you can use the #Middlewares() decorator.
Just put what you had in a app.use() to the #Middlewares() decorator.
You can define your Middleware / Middlewares like this:
import { Request, Response, NextFunction } from 'express';
// ... controller logic ...
// #Get('/endpoint') | #Post('/endpoint') etc.
#Middlewares([
(req: Request, res: Response, next: NextFunction) => {
console.log(req.headers);
next();
},
(req: Request, res: Response, next: NextFunction) => {
console.log('Second middleware, but we can also use only one!');
next();
},
])
// getEndpoint(): string {
// return 'Hello World!';
// }
// ... controller logic ...
Also remember to have set the experimentalDecorators to true in your tsconfig.json.1
1 https://github.com/lukeautry/tsoa/pull/1123#issuecomment-1018251162

How to access Response object in NestJS GraphQL resolver

How can I access pass #Res() into my graphql resolvers?
this doesn't work:
#Mutation(() => String)
login(#Args('loginInput') loginInput: LoginInput, #Res() res: Response) {
return this.authService.login(loginInput, res);
}
#Res() is for HTTP Requests. To access to res object you'd need to first make sure it is added to the context for graphql by using context: ({ req, res }) => ({ req, res }) in the GraphqlModule's options, and then you can use #Context() ctx to get the context and ctx.res to get the response object

Resources