Pitfall

Express.js is a lightweight HTTP framework for node.js that allows you to create a variety of applications, from a standard website to a REST API. It gets out of your way with a minimal API that you fill in with your custom needs.

The structure of ExpressJS is this: everything is “middleware”. If you’ve built an Express app, or read an Express app tutorial, you’ve probably seen code like this:

This code wires middleware to your application. So what is Middleware?

What is Middleware?

Middleware is a function that receives the request and response objects of an HTTP request/response cycle. It may modify (transform) these objects before passing them to the next middleware function in the chain. It may decide to write to the response; it may also end the response without continuing the chain.

In other frameworks “middleware” is called “filters”, but the concept is the same: a request, response, and some transformation functions.

A very simple middleware function looks like this:

This is middleware at its simplest: a function with a signature of (req, res, next). In this particular example, a simple logger prints some information about these requests to the server console, and then continues the chain by calling next().

The job of Express is to manage your chain of middleware functions. All middleware should achieve three things:

  • It should be a function that does something awesome
  • It’s well-documented
  • It can be easily mixed into your existing Express application

The “Hello, World!” of Middleware

As you write your own middleware you will run into some pitfalls, but fear not! I will cover them in this article, so you know if you’ve fallen into one. ๐Ÿ™‚

In our example application, we want two simple things to happen:

  • Say “hello” and “goodbye” on all the responses.
  • Log all the requests.

Let’s get started! Here is a basic shell of an Express application:

This Express application doesnโ€™t do anything by itself; you need to add some middleware! We’ll add our logger (the one you saw in the introduction):

Good to go, right? When we run our server and make a request of it (using Curl in the terminal), we should see a log statement printed in the server console. But if you try, you’ll see this from your request:

And this from your server:

We saw the server logging, but Curl gets a ‘Not Found’ error. What happened?

Pitfall #1 – “Not Found” means “Nothing else to do”

Pitfall1

While we did the good thing of calling next(), no other middleware has been registered and there is nothing else for Express to do!

Because we have not ended the response, and there are no other middleware functions to run, Express kicks in with a default “404 Not Found” response.

The Solution: end your responses via res.end(). We’ll cover that in a later section.

Saying Hello

We’re going to write a new middleware function, named hello, and add this to our app. First, the function:

Then add it to your middleware chain:

Notice the difference between use and get? These mean different things in Express.js:

  • use means “Run this on ALL requests”
  • get means “Run this on a GET request, for the given URL”

So what happens when we make a request for /hello? Here’s what Curl would do:

And what the server logs:

Looks okay, right? But if you actually try this, you’ll notice that your Curl command never exits. Why? Read on…

Pitfall #2 – Not Ending The Response

Pitfall2

Our hello middleware is doing the right thing and writing “Hello” to the response, but it never ends the response. As such, Express will think that someone else is going to do that, and will sit around waiting.

The solution: You need to end the response by calling res.end().

We wanted to say “Bye” as well, so let’s create some middleware for that. In that middleware we will end the response. Here’s what the bye middleware looks like:

And now we’ll add it to the chain:

Now everything will work the way we want! Here is what Curl gives us:

And the server will log our requests as well:

Middleware: Mix and Match

When you create simple middleware functions with single concerns, you can build up an application from these smaller pieces.

Here’s a hypothetical situation: let’s say we’ve setup an easter-egg route on our server, named /wasssaaa (rather than hello). Of course, we want to know how many people hit this route, because that’s really quite interesting. But we don’t want to know if someone is hitting the hello route, because that’s not very interesting.

Besides, our marketing team can tell us that information from their analytics system (but they don’t know about our easter egg! Ha!)

We would re-write our midddleware wiring to look like this:

This removed the global app.use(logger) statement, and added it to just the /wasssaaa route. Brilliant!

Express.js Routers

Express.js has a feature called Routers – mini Express applications that nest within each other. This pattern is a great way of breaking up the major components of your application.

A typical situation is this: you have a single Express server, but it does two things:

  • It serves a few basic pages, such as a home page and user registration system
  • It serves an API that your customers use to access their information, perhaps from mobile applications, an Angular application, or some other service

The code and dependencies for the web pages are drastically different from the API service, and you typically divide up that code. You can also divide them into separate Express routers!

Hello World, with Routers

Following the situation above, let’s build a simple server that says Hello! to everyone on our website AND our API, but only logs requests for the API service. That simple app might look like this:

We’ve separated our API service by defining it as an Express router, and then attaching that router to the /api URL of our main Express application.

What happens when we run this? Here’s what Curl reports:

Looking good, right? But what does the server have to say?

Hmm.. it doesn’t say anything! What happened??

Pitfall #3: Ordering of Middleware is Important

Pitfall3

Express.js views middleware as a chain, and it just keeps going down the chain until a response is ended or it decides there is nothing left to do. For this reason, the order in which you register the middleware is very important.

In the last example we registered the bye middleware before we attached the apiRouter. Because of this, the bye middleware will be invoked first. Our bye middleware ends the response (without calling next), so our chain ends and the router is never reached!

The Solution: Re-order your middleware. In this situation, we simply need to register the apiRouter first:

With this, we now get what we expect. Curl reports the same as before:

But now our server logs the API request:

But notice something curious here: even though we have requested /api/hello, the logger reports /hello. Hmm…

Pitfall #4: URLs Are Relative to a Router

Pitfall4

A router doesn’t really know that it’s being attached to another application. If you really need to know the exact URL, you should use req.originalUrl. Or if you’re curious about where this route has been attached, use req.baseUrl (which would be /api in this example).

Debugging Middleware

In this article I’ve shown you some of the common pitfalls with Express.js middleware. This certainly will help you as you write your own middleware, but what about all that third party middleware that you put into your Express application?

If you’re using 3rd party middleware and it’s not working as expected, you’re going to have to stop and debug.

First, look at the source code of the module. Scan it for places where it accepts (req,res,next) and look for places where it calls next() or res.end(). This will give you a general idea of what the flow control looks like, and might help you figure out the issue.

Otherwise, check out Node Inspector and go down the step-by-step debugging path.

Pitfall5

So Much Middleware, So Little Time!

I’ll wrap this article with this advice: there’s a lot of middleware out there! Start browsing NPM for great node.js middleware! If you want some inspiration, here are some we love:

  • Morgan is a fully-featured logger for Express.js. It does much more than our trivial example!

  • Helmet is a collection of smaller modules, culminating in a one-stop-shop for securing your web application. You should install this one right now.

And of course (we’re a little biased), but we think Express-Stormpath will be a great addition to your Express.js application. It handles all the authentication and user management for your application, so you don’t need to build out user infrastructure from scratch. It takes about 15 minutes to get a full authentication system for Express with this tutorial – including all the login screens.

With that.. happy coding! Feel free to leave comments and questions below. ๐Ÿ™‚

Pitfall0