Posted on by & filed under Content - Highlights and Reviews, Programming & Development.

codeA guest post by Roman Shtylman, founder of Courseoff, an online student scheduling tool. Courseoff uses Express.js for all their web services. He has been involved in open source for many years and is a contributor to many open source projects, Express.js being one of them. His current development passion is for JavaScript and Node.js and he frequently evangelizes new tools and techniques in the JavaScript ecosystem. He can be found on Twitter @defunctzombie.

Middleware is the core concept behind Express.js request processing and routing. By understanding how middleware works, you can create more maintainble applications with less code. The moment a request is received by an Express.js app, it triggers various functions referred to as middleware.

What is middleware?

Middleware is any number of functions that are invoked by the Express.js routing layer before your final request handler is, and thus sits in the middle between a raw request and the final intended route. We often refer to these functions as the middleware stack since they are always invoked in the order they are added.

Take the most basic Express.js app:

The above Express.js app will respond with Hello World! to a request for / and Nope...nothing to see here for requests to /help.

Now, suppose you want to record every time you get a request. You could go to each route and add your logging logic, or you can use middleware!

Here we have added a new function to invoke with every request via app.use(). There are some important things to notice about this new function:

  • Middleware is a function, just like route handlers, and it is invoked in much the same way.
  • The function signature looks identical to the one we used in our routes.
  • We added this function before our two route handlers because we want it to execute before either one.
  • We have full access to the same request and response objects that will find their way to the routes.
  • We used a third parameter, called next as a function to indicate that our middleware was finished.
  • We can add more middleware above or below using the same API.

We will revisit several of these items in more detail. This is only a basic example showing how to log every request your applications receive. Middleware can be as simple as one line, or as complex as session handling. Middlware is commonly used to perform tasks like body parsing for url-encoded or json requests, cookie parsing for basic cookie handling, or even building JavaScript modules on the fly.

When adding a new piece of middleware, read the documentation on how the middleware may affect the request or response objects. Remember that middleware has access to both of these objects and may modify or add properties.

The next() argument

Earlier you saw middleware call a next argument that was provided as the 3rd argument to the middleware function. In order for the request to continue processing (other middleware or even our route handlers) you must call this argument; simply letting the function finish execution is not enough.

The reason next is exposed and must be explicitly called is for middleware, which performs I/O or async operations. Express.js has no way of knowing when your operation is complete before it can continue to the next middleware or route.

Imeagine a scenario where you wanted to load a session from the database before processing any request.

Without the requirement to call next, Express.js would have no way of knowing when your database lookup was complete. In our example, you call next once you have a session loaded from the database informing the Express.js routing layer that the next middleware or route can be invoked.

Limiting paths for middleware

Up till now you have seen how to add middleware for every request, but what if you want to limit middleware to certain paths. Let’s say that routes under /users need some special middleware. How can you accomplish that?

app.use() accepts an optional path parameter just like the app.get() and other routes. The major difference, though, is how this path parameter is treated, as a prefix. If we were to pass /users to an app.get(), our function would only be invoked when someone visited exactly /users, however, when we pass /users to app.use(), any request that starts with /users will invoke our function!

We can easily get the sub-path under /users via the req.path property that is set by the Express.js routing layer.

When a requests for /users/daily is processed, req.path will be /daily in middleware. Note that req.path will be /users/daily in our route handler because req.path stripping is a property of the .use() method.

Middleware Pitfalls

Here are some common pitfalls to watch for when working with middleware.

Order matters

Remember that order matters. The following example shows middleware that won’t execute for GET requests, but will for POST requests simply by ordering it differently.

While not always a pitfall, it is important to understand that even though app.use() is invoked for every HTTP verb, middleware is processed in order with route handling. Since our route handler for GET responds to the request, our middleware will never run for GET requests, but our POST handler is after the middleware, thus allowing it to be invoked first.

Forgetting next()

If you have just added some middleware and when testing your page or API it seems to hang, or is never responding, then you have likely forgotten to call next. Because Express.js routing has no idea that your middleware is done, it will never proceed to call any middleware or routes that follow.

Overriding properties

Remember that the request and response arguments to all middleware and routes are the same instance. This means that if you have two middleware that modify the object properties in different ways, they may cause errors in your app. Be mindful of modifications your middleware make to the properties.

Conclusion

Here is a brief recap of what was covered in this post:

  • Middleware is always invoked in the order added.
  • You can have multiple middleware for the same path.
  • Middleware has full access to the request and response objects.
  • Be mindful of middleware overriding fields of other middleware.
  • Middleware can be skipped by using the next function.

And here are some useful tips to consider when using Express.js:

  • Always use the req, res, and next signature, even in routes where you don’t call next.
  • Pass errors to next so that they can be handled separately.
  • Look into express.Router() for isolated middleware stacks.
  • Middleware can be used to limit or record total response time if you want to bail early.

Look below for some great books that cover Express.js or view the Safari Node.js library.

Not a subscriber? Sign up for a free trial.

Safari has the content you need

Professional Node.js: Building Javascript Based Scalable Software begins with an overview of Node.js and then quickly dives into the code, core concepts, and APIs. In-depth coverage pares down the essentials to cover debugging, unit testing, and flow control so that you can start building and testing your own modules right away.
JavaScript Programming: Pushing the Limits delivers a compelling tutorial, showing you how to build a real-world app from the ground up. Experienced developers who want to master the latest techniques and redefine their skills will find this deep dive into JavaScript’s hidden functionalities gives them the tools to create truly amazing and complex applications.
Smashing CoffeeScript is a full-color, practical book that explains the CoffeeScript language, syntax, and processes, and will soon have you producing concise and quality code. Ultimately, you’ll create RIAs and mobile apps faster, with less hassle.
Node.js Recipes: A Problem-Solution Approach is your one-stop reference for learning how to solve Node.js problems. Node.js is the de facto framework for building JavaScript-powered servers. You will first be introduced to this exciting technology and what it can do, then learn through comprehensive and easy-to-follow recipes that use a problem-solution approach. This book teaches you to fully use the Node.js API, and leverage existing modules to build truly exciting projects.

Tags: Express.js, function, Javascript, middleware, next argument,

3 Responses to “Express.js Middleware Demystified”

  1. ketavine

    This is by far the best article on Express.js I’ve read so far. Thank you for sharing your experience, it was a delight to read. I’ll be checking out those books on Node.js you’ve attached to this post.

  2. Anthony

    Thanks for this Roman! finally i understand clearly the “use” of middlewares.

  3. Xavier

    By far the best introduction I have read on middleware. Thanks a lot for that!