If you go to the express.js website, which by the way is pretty great in terms of documentation, you'll notice that it touts itself as a fast, un-opinionated, minimalist framework. What they mean by minimalist is that express barely does anything besides the route matching and calling what is referred to as middleware. So, building an express app is just a matter of orchestrating various pieces of middleware to work in concert together and with the application itself.
While middleware might be a new term for you, we've actually been using it we've actually been using it the entire time we've been building this application. Essentially any time you see app.use, app.get, anything like that, everything that you pass into those calls is middleware. You've got the optional mount path to tell it which paths to act on, and then you have the middleware function itself.
We've got our profile pics path here is using express.static, which actually built-in middleware that ships with Express itself, that's sort of the only piece that ships with it. Then we're using a third-party middleware in our body parser here, so we downloaded that from NPM, we required it into our application, and we're using it to parse out the request bodies for our put request, then all these things down here are custom middleware that we have defined ourselves. We're fully controlling that.
You'll notice that everything here starts with app., so these are all application level middleware. Over here, in our username file, we have router level middleware, so anything that's attached to an instance of an express router is router level middleware. While we're in here, I did want to show one use case which we really didn't cover before, which is that you can use the use method, and actually omit the mount path all together.
In this case it's going to fire for every request that this router handles regardless of the path. We'll add some additional longing information here, and we should see that this should fire for our root path and our edit path. If we go over and load up our app, go into here, and navigate to this user's edit path, you can see that we're getting information for both the route route, and the edit route. That's one advantage of using the use method instead of the all method like we were using before.
Now the one type of middleware that we have not covered so far is what they refer to as error handling middleware, and that's exactly what it sounds like. If you define a piece of middleware that has four arguments, error being the first one, but really the important part is that there's four, because that's how Express recognizes it as error handling, that will then be used when any errors happen in the application.
In this case, we're going to define our own error handling and just log out the stack trace, and then we'll send a response back to the client that has a status of 500 and just says, "Something broke." In order to trigger this error, we're just going to get rid of our verifyuser call so that we don't have any safeguards in place. If we go here, this is fine, if we change it to an invalid user, we get, "Something broke." If we go look in dev tools we can see that that request did come in with a 500 status.
That gives us the ability to gracefully handle errors in our application. What happens if you don't handle these errors in your application? As it turns out, Express defines its own built-in error handling middleware, so if we delete our error handler and go back and refresh this page, you can see that we actually get that stack trace right in the browser.
That is Express' default error handling middleware, what it does is it sends the stack trace to the browser, and that's really helpful when you're in development, but you can see here there's all types of path information and other things that we probably wouldn't want an actual user of our application to see. The Express authors have anticipated that, and so this will only be the behavior of the default error handler if you're not running your app in production.
If you run your app in production mode by setting the node end variable to production, then we won't leak that information to the client. It's just going to tell them "Internal Server Error," you're not exposing any potentially dangerous information there. I mentioned that the Express site is really great in terms of documentation. They also have a good list of some of the various middleware choices that are available out there.
We've got our body parser here that we're using already, there's middleware for handling cookies and sessions, authentication logging, there's all kinds of stuff. Definitely check that out, but there's probably countless, hundreds if not thousands of other middleware packages out there for use as well.
Just to recap, we've got app level middleware, router level middleware, and if we go ahead and undelete that, we've got our error handling middleware. Those are the types of middleware that you need to be familiar with to be productive and professional with Express.