I am familiar with Express but new to Restify. Restify's document has many examples calling next() after res.send() as below:
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
This looks like a recommended pattern by some Restify experts as well:
The consequences of not calling next() in restify
What's the real use case of doing this? After you call res.send(), is there anything a handler next in the chain can do?
After I did some more research, I think I found an answer.
Only practical use case of calling next() after res.send() is when you want to install 'post-render' type middlewares to catch all transactions after route handers finish their job.
In other cases, it simply adds unnecessary overhead for every and each request because it scans the rest of routes to find a next match.
Most middlewares are 'pre-render' type, which don't need next() call anyway. Even for post-render type middlewares, depending on voluntary calls of next() is simply too risky. You'd rather want to use more error-proof method like https://github.com/jshttp/on-finished instead.
Calling next() after res.send() is a bad practice causing unnecessary overhead in most cases. It should be used only when it is absolutely needed and you know what you are doing.
Related
I'm reading the GitHub https://github.com/goldbergyoni/nodebestpractices and trying to apply the tips on my project. Currently i'm working on the "1.2 Layer your components, keep Express within its boundaries" tip, but I have a question.
I'm using routes/controllers, and using this tip (1.2), a route with multiple middlewares will look like this.
router.post("/do-multiple-stuff",
(req, res, next) => {
stuffController.getStuffDone(req.body.stuff);
next();
},
(req, res, next) => {
stuffController.getOtherStuffDone(req.body.otherStuff);
return res.send("stuff done");
});
Is this correct? Or there's a better way to do this?
Thanks! <3
The point of that 1.2 section is to create your business logic as a separate, testable component that is passed data only, not passed req and res. This allows it to be independently and separately tested without the Express environment around it.
Your calls to:
stuffController.getStuffDone(req.body.stuff);
and
stuffController.getOtherStuffDone(req.body.otherStuff);
Are indeed making that proper separation between the web and the business logic because you aren't passing req or res to your controller. That looks like it meets the point of the 1.2 training step.
The one thing I see missing here is that there isn't any output from either of these function calls. They don't return anything and since you don't pass req or res to them, they can't be modifying the req object (like some middleware does) and can't be sending a response or error by themselves. So, it appears that these need a mechanism for communicating some type of result back, either a direct return value (if the functions are synchronous) or returning a promise (if the functions are asynchronous). Then, the calling code could get their result and do something with that result.
I have a basic misunderstanding regarding asynchronic calls using express and middlewares and i would really appreciate some help understanding it.
Suppose we have this code:
var express = require('express')
var cookieParser = require('cookie-parser')
var app = require('express')
var router = express.Router()
app.use(function timeLog (req, res, next) {
req.requestTime = Date.now()
next()
})
app .use(express.json());
app .use(express.urlencoded());
app.use(cookieParser())
router.post('/hello', function (req, res) {
//write async to file
res.send('bye')
})
Now, when the client calls this endpoint "hello":
are the middlewares which defined in App-level called asynchronicaly? I understood that they do(because they are called "Callbacks" in the documentation... so basically before reaching the router: parsing cookies, parsing json to req.body and adding req.requestTime will run asynchronicaly and then will be routed to '/hello' end point.
after routing, is the callback will run asynchronicaly? if yes, then how in this case the request is not left hanging? i see that the response is being terminated inside a body of a callback... how this make any sense? :(
would somebody please explain to me this flow?
I will try to explain how I understood "async calls" through this code above: lets say alot of users trying to get this end point. all these calls added to the call stack, then because of these callbacks are async, then they are moved to event Queue/table and will be handled after the call stack will be "empty". if this is the case, how the first user will ever get a response? the requestTime done async, parsing the json done async and when reaching the router, the callback is done async.... so when the first user will ever get a repsone if all these async calls located inside the event Queue/table and they will be handled only after the callstack is empty? what am i missing here?
Thanks.
The middleware doesn't appear to be asynchronous of its own. In other words, as you said in your comment on another answer, it is not forcing each layer in the expressjs "stack" of middleware/handlers into a separate frame in the JavaScript event queue.
If you trace the next() function in a .use(), there are a couple of setImmediates fairly early on to handle "exit router" or "no more layers," but then you get into a while loop on a stack of handlers. This is happening at around this point in the code.
So if all your middleware was similar to this section, all middleware etc would happen in the same frame within the event queue:
app.use(function(req, res, next){
console.log('synchronous layer');
next();
});
Whereas a step like this next one would put the next into a separate frame in the event queue, and potentially allow the process to handle other frames that may be queued up.
app.use(function(req, res, next){
setImmediate(()=> {
console.log('setImmediate puts this next() into a separate frame in the event queue');
next();
});
});
I can't imagine this would normally be a problem. Most things that would happen in middleware that might take some time (a database call etc) are very likely all going to be happening asynchronously (in a way that puts the next into a new frame in the event queue). But it is something worth considering when you're adding middleware...
All those middleware are using the continuation passing style. So basically they COULD run asynchonous. But they don't have to. It depends on, whether those middlewares are doing some IO. You could take a look into the code to check how the functions behave exactly, but at least, this does not matter. Just keep in mind, that they COULD run asynchronous.
In express and connect, is it bad to use "next" in middleware if I do not need it? Are there any possible negative outcomes? Assume there is no middleware which will be called after this middleware, and therefore the next will not call anything. I know it is bad for modularity, as if you want to add a callback for another middleware it may be accidentally triggered by the next in this middleware. However, in this case next is bad for modularity anyway, as middleware often interact in unexpected ways.
As an example of an unneeded next, consider the sample MEAN.JS stack, constructed by the guys who originally came up with the stack's name. It seems to have some next callbacks which do not ever get called. Many are in the users controller, including the signin function:
exports.signin = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
})(req, res, next);
};
This function has a next callback defined. This next callback is then used by the passport.authenticate() custom middleware function as a parameter. However, this parameter is never used in the function itself. I have tried taking out the next definition from the function definition, as well as the custom passport middleware, and the route seems to still work. However, perhaps passport uses it in its authenticate() function, and leaving it out did not cause any trouble here but it may cause trouble in some cases.
I was recently looking at passport's tutorials on http://passportjs.org, and I came across a function in the section on custom callbacks on the authenticate page that looks almost exactly like the signin function in MEAN.JS. One difference was that it actually had some next callbacks (for error handling), so the next parameter was actually useful. Is it possible that the MEAN.JS app took a lot of code from passportjs.org's guide and changed it over time, but left in some vestigial remnants that do not do anything but were causing no harm? Or does the next parameter actually do something in passport.authenticate() that is not immediately obvious? Regardless of why this happened, does an extra next parameter in connect middleware cause any bad side effects if it is not used?
When writing middleware, the next parameter is optional. It's purpose is so that the next middleware in the chain will be called. If you want the current middleware to be the last one called for a given request, not executing the next parameter will accomplish that. This is fine for code that you write for yourself, but it's typically better to always execute the next parameter in middleware that may be used elsewhere because you don't know what else they could be adding.
For example, maybe you wanted to add some kind of logging that happens after a request is completed. If your middleware that runs before the logging middleware doesn't execute next, it won't be logged.
http://expressjs.com/api.html#middleware
Not executing next will simply not start the next middleware. There are no other side effects of not executing it other than those caused by not moving to the next middleware (for example, if the response hasn't ended yet, not calling next will result in a timeout.)
Hellow I have code in my app.js, looking like that:
app.use('/someurl', require('./middleware/somemodule'));
-app.use instead app.all
and module looks like:
if(process.env.BLALAL === undefined){
throw "Error: process.env.BLALAL === undefined";
}
module.exports = function(req, res, next){
...
}
is it a bad practice ?
As said on the express api reference:
app.VERB(path, [callback...], callback)
The app.VERB() methods provide the routing functionality in Express,
where VERB is one of the HTTP verbs, such as app.post().
app.use([path], function)
Use the given middleware function, with optional mount path,
defaulting to "/".
The "mount" path is stripped and is not visible to the middleware
function. The main effect of this feature is that mounted middleware
may operate without code changes regardless of its "prefix" pathname.
IMO
The functionality may be nearly the same, but there is an underlying semantic meaning. The routes itself should be set through the app.VERB api, while any middleware should be set through the app.use api.
Normally middlewares modify the request or response objects, or inject functionality from other module that may answer the request, or not.
connect.static is a good example. It could be really an app or an HttpServer by itself, but is injected as middleware on other app object.
I personally don't like require inside other commands then var bla = require('bla');, it makes code much worse readable in my opinion and you did not get anything in return.
I am not sure what was your intention, but if your code depends on environment variable, it is better to throw immediately than later when your route is called. So app.use is better then app.all. But I don't understand why aren't you simply test your condition inside app.js and why you hide it in somemodule.
The docs read:
The app.VERB() methods provide the routing functionality in Express,
where VERB is one of the HTTP verbs, such as app.post(). Multiple
callbacks may be give, all are treated equally, and behave just like
middleware, with the one exception that these callbacks may invoke
next('route') to bypass the remaining route callback(s). This
mechanism can be used to perform pre-conditions on a route then pass
control to subsequent routes when there is no reason to proceed with
the route matched.
What do they mean by "bypass the remaining route callbacks?"? I know that next() will pass control to the next matching route. But... what function will get control with next('route')...?
I hated it when I answer my own question 5 minutes later.
next('route') is when using route middleware. So if you have:
app.get('/forum/:fid', middleware1, middleware2, function(){
// ...
})
the function middleware1() has a chance to call next() to pass control to middleware2, or next('route') to pass control to the next matching route altogether.
The given answer explains the main gist of it. Sadly, it is much less intuitive than you might think, with a lot of special cases when it is used in combination with parameters. Just check out some of the test cases in the app.param test file. Just to raise two examples:
app .param(name, fn) should defer all the param routes implies that if next("route") is called from a param handler, it would skip all following routes that refer to that param handler's own parameter name. In that test case, it skips all routes refering to the id parameter.
app .param(name, fn) should call when values differ when using "next" suggests that the previous rule has yet another exception: don't skip if the value of the parameter changes between routes.
...and there is more...
I'm sure there is a use-case for this kind of next('route') lever, but, I agree with previous comments in that it certainly makes things complicated and non-intuitive.