Exit after res.send() in Express.js - node.js

I have a fairly simple Express.js app with a login component that I'd like to exit early if login fails. I'm seeing indications that the app isn't doing that and I haven't found a definitive answer that indicates whether calling res.send() halts any further processing. Here's my code as it stands now:
client.login( username, password, function( auth, client ) {
if( !auth ) {
res.send( 401 );
}
// DO OTHER STUFF IF AUTH IS SUCCESSFUL
}
If I read the source code correctly, it should end the request (aborting further processing), but I'm new to node, so I'm not quite ready to trust what I think I'm reading. To boil it down, I guess I'm mostly looking for a definitive answer from a more trustworthy source that my own interpretation of unfamiliar source code. If send() doesn't abort processing, what's the right way to do that?

Of course express can not magically make your javascript function stop executing from somewhere else.
I don't like the next([error]) solution because I think errors should be only used for circumstances you usually don't expect (like an unreachable database or something). In this case, a simple wrong password would cause an error. It is a common convention to not use exceptions/errors for ordinary control flow.
I therefore recommend to place a return statement after the res.send call to make your function stop executing further.
client.login( username, password, function( auth, client ) {
if( !auth ) {
res.send( 401 );
return;
}
// DO OTHER STUFF REALLY ONLY IF AUTH IS SUCCESSFUL
}

If you are using express as your framework, you should call next() instead.
Each handler in express receives 3 parameters (unlinke 2 for basic http) which are req, res and next
next is a function that when called with no arguments will trigger the next handler in the middleware chain.
If next is called with an arguments, this argument will be interpreter as an error, regardless of the type of that argument.
Its signature is next([error]). When next is called with an error, then instead of calling the next handler in the middleware chain, it calls the error handler. You should handle the 401 response code in that error handler. See this for more info on error handling in Express
EDIT: As #Baptiste Costa commented, simply calling next() will not cease the current execution but it will call on the next middleware. It is good practice to use return next() instead to prevent Node from throwing errors further on (such as the can't set headers after they are sent - error). This includes the above suggestion of error throwing which is common:
return next(new Error([error]));

For your specific case you can just add the 'else' statement:
client.login( username, password, function( auth, client ) {
if( !auth ) {
res.send( 401 );
}else {
// DO OTHER STUFF IF AUTH IS SUCCESSFUL
}
}
Or, in general, you can use 'return':
return res.send( 401 );

in these cases , i tend to use a try...catch bloc .
client.login( username, password, function( auth, client ) {
try{
if(error1){
throw {status : 401 , message : 'error1'}
}
if(error2){
throw {status : 500 , message : 'error2'}
}
}catch(error){
res.status(error.status).json(error.message);
}
}

Simply do something like this to stop further execution.
function (request, response, next) {
var path = request.body.path;
if(path === undefined){
response.status(HttpStatus.BAD_REQUEST);
response.send('path is required!');
}
next(response)
};

You only need to do a return to end the flow:
return res.send( 401 );
That will send the 401 response back and won't proceed forward in the flow.

Why is no-one suggesting using an 'else' block?
if(!auth){
// Auth fail code
res.send 'Fail'
} else {
// Auth pass code
res.send 'Pass'
}
'next' is used when creating your own middleware for the "app.use(function(req, res, next));".
If you have set up a route like "app.get(route, function(req, res));" then the code in the function is where you can have the code you are specifying without needing to use 'next'.

Related

Error Handling in nested API Calls with express and nodeJS

I have 3 microservices with an API interface with the goal to create a new user in my system.
service1 --> is the main service and will orchestrate the request along the other services
service2 --> will create the user in Firebase
service3 --> will create the user in the Data Base
The frontEnd will call service1 and it will call first the service2 and then the service3. With the result, service1 will respond the frontEnd.
If each service respond 200-OK everything works fine, the problem is the error handling.
When service2 respond 401- "User already exist in system" to service1, I only can retrieve from error "message: Request failed with status code 401" and not the text "User already exist in system" sent by service2.
How can I do for service1 will pass through the error code and error message sent by service2? 401- User already exist in system
service1.js
app.post('/createAdminAgent', async (req, res) => {
let body = req.body;
try {
const response_createAgentFirebase = await axios.post(service2URL + '/createAgent', req.body); //the user exist and will respond 401
const response_createAgentBDD = await axios.post(service3URL + '/createEnterpriseAndAdminAgent', req.body);
res.status(200).send(response_createAgentBDD.data);
} catch (error) {
res.status(400).send(error); // how can I get here the text "User already exist in system" and the status code 401 sent by service2
}
});
service2.js
app.post("/createAgent", async (req, res) => {
createAgentOnFirebase(req.body, async function(err, firebaseResult) {
if (err == null){
res.status(200).send(firebaseResult);
}else{
res.status(401).send({
status: 401,
error: 'User already exist in system'
})
}
})
})
To answer the question that you have in the comment of the try { } catch() { } block of your main service route handler:
"how can I get here the text "User already exist in system" and the status code 401 sent by service2"
You should pass any errors to a custom error handling middleware function (which you can define yourself) and handle errors within those functions, rather than in the route handlers themselves. Trying to handle errors within the route callbacks themselves gets messy, and often leads to duplicative code.
Triggering Error Handlers
To trigger the next express error handler in the stack, all you need to do is pass an error to the next callback provided as the last argument in the route handler callback. If you do not have any custom middleware installed, express will use the default which is already included in the middleware stack.
Using Custom Error Handlers
To use a custom function, you'll trigger it the same way, but you'll have to define the function yourself with the following criteria:
it must take 4 arguments: (error, req, res, next) => {}
it must be attached at the end the middleware stack
From there, you can parse out data from the req and error objects to obtain more information about the request and what error was thrown during its processing. More about this implementation below.
Starting with the basics, from the expressjs documentation:
Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously. Express comes with a default error handler so you don’t need to write your own to get started.
Looks like you're mainly concerned with handling asynchronus errors. You can attach a custom error handler to the end of your middleware stack that takes 4 arguments, like so:
// apiRouter would contain all your routes
app.use('/api/v1', apiRouter);
// error handler gets attached at the end of the stack, after your routes
app.use((err, req, res, next) => {
// custom error handling logic here
// make sure to end the connection, or the request will hang
});
and express will automatically call that middleware anytime you pass an error to the next function, from any one of your route handlers.
Another thing to note from their documentation:
Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error.
Depending on your version, you may begin to encounter this behavior (if you're returning Promises). In that case, for those Promises, your errors are being handled by the default express error middleware.
If you pass an error to next() and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
Default Error Handler Description
When an error is written, the following information is added to the response:
The res.statusCode is set from err.status (or err.statusCode).
If this value is outside the 4xx or 5xx range, it will be set to 500.
The res.statusMessage is set according to the status code.
The body will be the HTML of the status code message when in production > environment, otherwise will be err.stack.
Any headers specified in an err.headers object.
Suggestion
In your case, I would leverage the ability to create multiple error handlers and provide a "catch-all" at the end of that chain. When catching errors, you can add custom props that gives hints to error handlers as to what they are dealing with. Explicit if statements within the handlers can check for those custom props and handle errors you expect to see. Unforeseen errors will fall to the next error handler (provided you're passing the error to it by using next).
app.use('/api/v1', apiRouter);
...
app.use(errorLoggingHandler);
app.use(errorResponseHandler);
app.use(errorCatchAllHandler);
Sorry if I did't explain the idea correctly. My goal is to pass through the error response from service2 to service1 when an error has occurs. I solved usng res.status(error.response.status).send(error.response.data) in service 1 inside the catch.
Thanks!

Handling request simltaneously in nodejs and passing it's response using only one res.send

I am developing an API which takes input in XML containing IDs for media and gives output in XMLform with details of given IDs. I am facing a problem while sending the response of second simultaneous request; here the second request goes into loop showing "loading" on postman.
What I am doing is calling a function in app.post which parses the media and gives output in the callback and send it using res.send, but it works only for single request.
While doing parallel request to same API either it goes in loop or it gives can't set the headers after they are sent as I am using res.send but res.send is the only way which I can use to send the response (even the next doesn't work).
var getCompositeData = function(req, res, next){
abc.getData(req.body, function(err, xmlOutput){
if(err){
console.log("error");
} else {
xmlData = xmlOutput
return next()
}
}
app.post(apiUrl, [
rawBodyParser({
type: 'application/xml'
}),
app.oauth.authorise()
], getCompositeData, function (req, res) {
res.setHeader('Content-Type', 'application/xml');
res.send(xmlData);
});
There are several issues with your code:
if (err) {
console.log("error");
}
If an error occurs, you still need to make sure a response will be sent back, otherwise the request will stall until a timeout happens. You can pass an error to next, and Express will handle it:
if (err) {
return next(err);
}
Next problem:
xmlData = xmlOutput
xmlData is an undeclared variable, which gets overwritten with each request. If two requests happens at (almost) the same time, it's likely that one client gets back an incorrect response (remember, Node.js runs JS code in a single thread; there is not thread-local storage so xmlData gets shared between all requests).
A good place to "store" this sort of data is in res.locals:
res.locals.xmlData = xmlOutput;
return next();
// and later:
res.send(res.locals.xmlData);

SendFile issues with respect to control flow in Express Middleware

Here is relevant portion of my code, simplified for narrowing the issue:
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
break; //break1
case 'njm' : break; //break2
default : console.log('default');
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}
Question is this: In case extension is html, for example, I would not expect middleware2 to be called at all but it does!
It appears that sendFile initiates the sending of the file and control execution falls thru before the sendFile's callback is called. If I replace break1 by next() or return next() that would be equally flawed - Control will go to next middleware2 before sendFile's callback is executed. How do I stop middleware2 from getting called for the first set of extensions? Also, if extension is 'njm', even without a next(), middleware2 is called. Why?
Please do not suggest using Express static middleware because I have some logic involved in serving different file types which is more complex then the simplified scenario given above.
res.sendFile() is a bit unique. If you don't pass it a completion callback, then it will call next() for you. See details later in this answer.
What you are reporting is opposite of how Express says it works so I think there must be something that is not quite happening the way you report it.
The whole point of the Express middleware is that any given middleware call gets a chance to field the request and then it either handles the request by generating a response or if it wants the middleware chain to continue, then it calls next(). If next() is not called, then the middleware chain stops and nothing else is called in the current middleware chain. If this is application level middleware (with app.use()), then there should be no further app level middleware processing if you do not call next() from your middleware.
Here's a quote from the Express middleware page:
If the current middleware does not end the request-response cycle, it
must call next() to pass control to the next middleware, otherwise the
request will be left hanging.
This is a pretty good article about Express middleware: Express Middleware Demystified which helps explain a lot more of the details. It also confirms that if you don't call next() then no more handlers will be called in the middleware chain.
There is one special case with res.sendFile(). If you don't pass it a completion callback, then it will call next() itself. If you pass it the completion callback, then it will not call next(). This does not appear to be well documented, but if you look at the res.sendFile() code here, you can see how it works.
One thing to watch out for with your debugging is that sometimes the browser issues more requests than you may realize. For example, when you first hit a homepage of a site, the browser may ask for the website favicon which causes an extra request to hit your web server. So, I'm wondering if your console.log() debugging is confusing you because perhaps there is more than one request coming in, not a single request that is going through both pieces of middleware. Also, a cross origin Ajax call may request AJAX options before requesting the actual Ajax call too.
You can differentiate multiple requests like this and more accurately see whether it is actually going from middleware1 to middleware2 on the same request:
var reqCntr = 1;
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware1: " + req.reqCntr);
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
// return here because the request is now handled
return;
case 'njm' : break; //break2
default : console.log('default');
break;
}
// the request was not handled so call the next link in the middleware chain
next();
}
function middleware2(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware2: " + req.reqCntr);
}
Also, it seems like the middleware1 cases where you are not handling the request should call next() so I've modified the above middleware1 to do that. If you handle the request in the switch statement, then return. If not, it will fall through to a call to next().
Once you write app.use(middleware2), middleware2 will be used for all routes on app once middleware1 is completely executed.
As you want to use middleware2 conditionally I would suggest you to use the following method:
app.use(middleware1);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' : middleware2(req, res, next);
break;
case 'html': res.sendFile(res.originalUrl,function(err) {});
break;
case 'njm' : middleware2(req, res, next);
break;
default : middleware2(req, res, next);
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}

How to force or create a POST request from Code on Node.js

As a learning exercise to understand Node.JS and express.js I am writing a very simple application that handle users creation, deletion and sessions.
This is the code when a user deletes his profile:
app.del ('/users/:name', loadUser, restrictUserToSelf, function ( req, res, next ) {
connection.query (
'DELETE FROM test_table WHERE User = ? ',
[req.user.User],
function ( err ) {
if (err) {
throw err;
}
console.log ( 'User deleted:'+req.user.User );
});
res.redirect('/users'); // Replace this line with POST to destroy the session
});
This code is working fine. I want to add a line to destroy the session after the user is deleted, however I already have a code that perform that work when the user log out
app.del ('/session', function ( req, res, next ) {
req.session.destroy();
res.redirect ('/users');
});
So in my mind all I have to do is force a POST to /session and change the _method to DELETE with Method Override.
I have look on Goggle but could not find how do I force that post and how do I change the _method from the code?
Can you guys help me please?
Thanks
why don't you call the req.session.destroy() before your res.redirect('/users') ? I think that would be the simplest solution.

Express Error Handling - Get Status Code

If I define error handling middleware with express like so:
app.use(function(err,req,res,next){
// Do Stuff
});
How do I get the HTTP status code of the error(or do I just assume is's a 500)?
Thanks,
Ari
In short, your code has to decide the appropriate error code based on the specific error you are handling within your error handling middleware.
There is not necessarily an HTTP status code generated at this point. By convention, when I call next(error) from a middleware function or router handler function, I put a code property so my error handling middleware can do res.status(err.code || 500).render('error_page', error); or something along those lines. But it's up to you whether you want to use this approach for your common 404 errors or only 5XX server errors or whatever. Very few things in express itself or most middleware will provide an http status code when passing an error to the next callback.
For a concrete example, let's say someone tried to register a user account in my app with an email address that I found already registered in the database, I might do return next(new AlreadyRegistered()); where the AlreadyRegistered constructor function would put a this.code = 409; //Conflict property on the error instance so the error handling middleware would send that 409 status code. (Whether it's better to use error handling middleware vs just dealing with this during the normal routing chain for this "normal operating conditions" error is arguable in terms of design, but hopefully this example is illustrative nonetheless).
FYI I also recommend the httperrors npm module which provides nicely-named wrapper classes with a statusCode property. I have used this to good effect in a few projects.
You could try to define the status code in the route:
app.get('/force-error', function(req, res) {
res.status(400)
next(new Error('Bad Request.'))
})
Then:
server.use(function serverErrorHandler (err, req, res, next) {
const code = res.statusCode
// if status 200 change to 500, otherwise get the defined status code
res.status(code === 200 ? 500 : code)
// check if it's a ajax request
if (req.xhr)
res.json({
error: {
status: res.statusCode,
message: err.message,
stack: err.stack,
}
})
else
next(err)
})

Resources