Order of the error-handling and 404-handling middlewares? - javascript

The express.js website confused me, because there are two contradictory statements:
You define error-handling middleware last, after other app.use() and routes calls
– /guide/error-handling.html
and
All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response
– /starter/faq.html
It seems to be telling me that both of these middleware layers should be the last ones in the stack...? Erm, so what, I am meant to add two app.use middleware layers last? That is not possible...
Anyway, obviously one of these pages forgot to mention the exception of the other, so I'd like to know: which middleware should I register last? My error-handler or my 404-handler?
I'd like these two functions, but I'm not sure which order they need to go in for express to work properly:
app.use(function(req, res, next) {
res.status(404).send('Sorry cant find that!');
});
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
Also I'm wondering, do I need to call next from within either handler?

The order doesn't really matter as your last middleware only gets called, when in some middleware before next(err) has been called. Your 404 middleware will always get called if nothing else has handled (and finished) the request.
And for your second question: no, you don't want to call next()in either of those as you finish the request with res.send().
Edit: I would leave the order like that though as the 404 middleware is not really an error handler.

Related

What exactly is "next()" in middleware and how does it work? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I'm following Net ninjas tutorial on node.js and I'm trying to make my own examples so I can get the concepts down in my head. When I do this I follow along with the GitHub source code on his profile. I got stuck on this part:
// middleware & static files
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
When I learn code, I make it my goal to know not only what works, but why it works. That being said, I have two questions:
Why can I get away with not using "next()" on the lines 1-3, but not 4?
Why is line 4 even necessary to begin with? Net ninja never explains it in his video where he talks about middleware.
The structure of an ExpressJS server looks like an onion, where each layer is a different Middleware. As shown here
A request to the server will go through every middleware in order. The next() function tells Express that the current middleware finished it's businness with the request and that the execution should continue.
All middlewares call the next() function, you don't see it on lines 1-3 because they are inside the corresponding middleware's code.
If you just do
app.use(morgan('dev'));
It means your "execution path" will be Request -> Morgan -> App -> Morgan -> Response.
Similarly, if you do
app.use(morgan('dev'));
app.use(debug);
Your "execution path" will be Request -> Morgan -> Debug -> App -> Debug -> Morgan -> Response.
You may have noticed that the middlewares are shown twice on the path. That's due to EspressJS structure and it means that a middleware can have more than one next(). The first next() is called after processing the Request and the second one is called after processing the Response.
app.use((req, res, next) => {
// Start some work
next(); // Stop work and continue to the next middleware
// Resume work
next(); // Finishes execution and continue to the next middleware
});
Each request will go through all the middlewares that you have specified and in the exact order in which they are specified.
When you are creating your own middleware, you can use the req, res and next inside it. Sometimes one middleware will not do whole logic, but only the part of it, so that middleware can modify the req and res and then it can call next(). next() means that modified req and res objects will be passed to the next middleware.
Also, when you want to handle an error, you can just pass the error with next(error) and then the Error Handler will be triggered.

Proper usage of Express' res.render() and res.redirect()

I am using a res.redirect('page.ejs'); and on my browser I get the message:
Cannot GET /page.ejs
I have not declared this in my routes file in the style of :
app.get('/page', function(req, res) {
res.render('page.ejs');
});
Should this be included in order for the res.redirect() to work?
When I do not use res.redirect() but res.render(), even if I have not the app.get() code, it still works.
so to understand this, let's look at what each of these methods do.
res.redirect('page.ejs');
// or, more correctly, you're redirecting to an *endpoint*
// (not a page. the endpoint will render a *page*) so it should be:
res.redirect('/page');
this will tell express to redirect your request to the GET /page.ejs endpoint. An endpoint is the express method you described above:
app.get('/page', function(req, res) {
res.render('page.ejs');
});
since you don't have that endpoint defined it will not work. If you do have it defined, it will execute the function, and the res.render('page.ejs') line will run, which will return the page.ejs file. You could return whatever you want though, it can be someOtherPage.ejs or you can even return json res.json({ message: 'hi' });
res.render('page.ejs');
this will just respond to the client (the front-end / js / whatever you want to call it) with the page.ejs template, it doesn't need to know whether the other endpoint is present or not, it's returning the page.ejs template itself.
so then, it's really up to you what you want to use depending on the scenario. Sometimes, one endpoint can't handle the request so it defers the request to another endpoint, which theoretically, knows how to handle the request. In that case redirect is used.
hope that makes sense and clarifies your confusion
(I'm not an expert on the inner-workings of express, but this is a high-level idea of what it's doing)
You should do res.redirect('/page')

What parameters does next() take in Express

I am currently building an API thanks to Express.js, and I still can not believe how amazing it is. I figured out how to use middlewares, handling requests and responses, how to go to the next middleware ... But there is something that triggers me a lot, which is next().
I know what next() is, I just can't figure out what kind of parameters can next() take, and what they will do. At first I thought it was to pass data to the next middleware, turned out I was wrong, there is req.locals for this.
Can someone enlighten me on this ?
You have three choices for calling next():
1. Continue routing. If you just want to continue routing to the next route handler in the chain that matches this route, then you just call it with no parameters:
next();
This is most often used in middleware:
app.use((req, res, next) => {
// set an item in the session and then continue routing
req.session.xxx = "foo";
next();
});
2. Abort routing with an error to your centralized error handler. If you want to set an error and have routing skip to your generalized error handler, then you can pass an error:
next(new Error("timeout contacting database"));
This will then invoke your general error handling route and pass it that specific error where your general error handling code can decide what to do. This allows you to centralize your error handling response code in one place. Examples of using next(err) are here.
You can see the doc for generalized error handling in Express for examples on how that works.
3. Skip route handlers in this router, continue routing in other routers. If you want to skip all route handlers in the current router, but continue with any other routes that might be registered, then you can do this:
next('route');
From the doc:
You can provide multiple callback functions that behave just like middleware, except that these callbacks can invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there is no reason to proceed with the current route.
If you repeatedly search for "next(" on this page of the doc, you will find lots of examples. There's an example of this usage here in the doc.
FYI, Express 5 may add some new uses for next() because it may return a promise that lets you know when routing is now completely done.

Does express app.use execute every time a path is heard on server.js

In my server.js file, where I may have many lines of code that use app.use, do these lines app.use execute every time a path is hit? I am a little confused on how this works when using the express router. If I have something like
var example1 = require('./js/exampleRoutes.js)
var example2 = require('./js/example2Routes.js)
app.use(express.static(process.cwd() + '/public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(methodOverride("_method"));
app.use(example1, example2);
app.listen(PORT);
Do all four lines of app.use execute everytime a path is hit, and depending on the path hit, it will redirect the program to either example1 routes or example2 routes?
exampleRoutes.js
router.get('/', function(req, res){
....
});
example2Routes.js
router.post('/create', function(req, res){
....
});
Does express app.use execute every time a path is heard on server.js
It depends upon whether you're using a path with any of your app.use() statements and it depends upon whether all the app.use() statements pass control onto the next handler or whether some of them purposely terminate the chain and handle the final response themselves.
All app.use() statements are registered as middleware handlers for all requests that hit that app object. If it has a specific path on it, then it will only be called if it matches that path. If it does not have a path (as in your examples), then it will be considered for every request.
When a given middleware handler is called, it is passed three arguments as in this example from the Express doc:
app.use(function (req, res, next) {
console.log('Time: %d', Date.now());
next();
});
Note, that last argument next. When a middleware function gets called, it has three main choices for how it's going to work:
It can do something and then let the request continue on to other handlers.
It can do something and then trigger an error (for example authentication failed or a require session cookie is missing).
It can do something and then send the final response (res.send(xxxx)) and not pass control on to other handlers.
The mechanism for passing control on to other handlers is by calling next() when you are done with your processing and ready for other handlers to get their crack at this request. If each middleware handler calls next() for each request they see, then ALL the app.use() handlers will get called for every single request. In the example above from the Express doc, you can see that this is a very simple middleware handler. All it does is log the time of the request and then it calls next() to pass control onto the next handler in the chain.
If one of the middleware handler does not call next(), then for that request, none of the handlers that come after it in the chain will get called for that request.
On a separate note, you can limit middleware to certain url paths only. Rather than calling
app.use(example1)
you can include a path as an argument such as:
app.use('/api', example1);
Then, this middleware will only be called for paths that start with /api.
Or, you can similarly use Routers to create branches of middleware. For example, if you have some middleware handlers that you only want to be called for requests that start with /api, then you can create a router for the /api prefix on the URL and attach the middleware handlers to that router instead of to the app object and then the middleware handlers on that router will only be called for requests that start with /api and are thus directed to that router.
// create api router
var router = express.Router();
// register middleware that is called only when requests go through this router
router.use(example1);
// register normal get handler
router.get('/whatever', function(req, res) {...});
// hook api router into the app
app.use('/api', router);

Who provides the next() function in Express middleware?

I'm confused about how next() works in Node.js and Express middleware.
There have been some other questions about middleware works, for example here, but I'm looking for a different answer.
The main question bugging me is, who is providing the next() function?
For example, in my standard generated express app, I'm given this code:
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
But who calls this function and what is the nature of the next() that it provides? How do I know what the next() will look like? I have no idea what next() does.
An Express application is essentially a series of middleware calls.
Middleware is a function with access to the request object (req), the
response object (res), and the next middleware in line in the
request-response cycle of an Express application, commonly denoted by
a variable named next.
As written above, Expressjs provides the next callback function. Next is just a way of calling the next middleware in the flow.
For many examples see Express's Using middleware

Categories