Learning Node.js, Part 3

In prior posts I had you creating web apps/servers via very simple logic. Framework software provides infrastructure support that allows you to create all of that a lot more quickly. Here I’ll take a look at using Express with Node.js.

There are many frameworks out there that you can choose from. If you like somewhat “heavy” MVC-type frameworks you could look at Geddy or CoreJS. There is also Ember.js (which used to be called SproutCore) and Flatiron. Probably one of the more popular at this time is a simple and minimal framework called Express. That’s the one I’ll go through here.

Installing Express

To get a feel for Express, the first step is to use the command-line version of the tool to generate an application. To use Express you can install it globally:

$ npm install -g express

At the time of writing, Express 4.0 is the newest version of the application and it operates a bit differently than prior versions in some respects, which means what you see in various tutorials may differ. Express always had a “scaffolding generator.” What this means is that you can run a command and a generator will provide a certain amount of so-called boilerplate code that just about all projects require. Starting with Express 4.0, however, you have to install an Express scaffolding generator separately:

$ npm install -g express-generator

When you install modules like this with the -g switch, npm will install the modules globally. That means they live in your master npm installation directory and should thus be available on your system path. To test this out, let’s create a throwaway project:

$ express test_app

Here I’m calling “express” as if it was an actual application. Which, in fact, it is. The reason I can call it is because I installed it globally. You will see output that says a test_app directory is created and a series of files will be created within it. Take some time to look over what got generated. A few important things to note. The express installation created a file called package.json. This is a basic JSON file that describes the application you are creating and any dependencies. Take a look at the generated package.json file. You’ll likely see something like this:

Notice all those dependencies there? The output from the express scaffold creation tells you that you should go into your new directory and run a command “npm install”. That command will read through that list of dependencies and install of them in a directory called node_modules in your test_app project. So let’s do that:

$ npm install

Once the application’s dependencies are installed, we can run the app. The express scaffold generator also created an index.js file and this is the starting point of your application. Run your server/app with the following command:

$ npm start

I should note some tutorials will show you that you should do this: node index.js. For this example, it doesn’t really matter. They are both equivalent. What happens now is that a server is started on port 3000. If you go to http://localhost:3000, you should see a simple page pop up welcoming you to Express.

You’ve created your first Express application.

Now let’s get ready to throw away our throwaway application. Yep, you heard me right: delete that test_app directory and let’s start over.

Building an App with Express

What I want to do now is start a new application, still using Express, but building it up from scratch so you have some idea of what is going on. Start by creating a new directory for your project: this will be the root directory for your project. Let’s just called it test_app as we did in the first example.

Again, please make sure you wiped out the test_server directory that we originally created. We’re going to build a simple project in here, essentially taking my examples from the last post and putting them in the context of Express.

What you saw from the first project is that npm manages project dependencies — as well as some metadata about the project — in a file called package.json. You can, of course, just create this file manually. We’re sort of going to do that but in a slightly easier way. Specifically, the easiest way to create this file is to run the following (from within the test_app directory):

$ npm init

This process will ask you a series of questions and generate a package.json file to get you started. For the “entry point” question, you can use your own filename if you prefer or just accept the default, which will be index.js. For this post, I’ll just assume you kept the default. If you take a look at the package.json generated, you will see it’s quite a bit more minimal than what we got with the scaffold generated project. Most obviously there are no dependencies specified as of yet. For example, mine looks like this:

The purpose of the package.json file is twofold: to describe your project and to list dependencies. Right now all we have is descriptions about the project. We’ll add some dependencies next.

Install Express — Locally

The first step will be installing Express. You might be wondering why I say that since we already installed Express above. Well, we did install Express — globally. However, if you look back to the original package.json file that was generated by the Express scaffold generator, you’ll see this line in it:

That means Express is installed as a local dependency of your project when you generate that project with Express. That makes sense, if you think about it. After all, your project has to have Express in order to use Express. The presence of “express” in the package.json file means that Express is installed locally as part of your project. So we’re going to do the same thing here. Run the following npm command:

$ npm install --save express

Running npm install will, as before, install the named package(s) in the node_modules directory. The npm packages that your project relies on will always reside in the node_modules directory and that directory can always be regenerated by an npm install command. When you specify the –save flag to the install command, npm will update the package.json file for you with the dependency that you are installing. Take a look at your package.json file now and you’ll see “express” listed as a dependency.

The caret (^) in front of the package versions indicates that any version that starts with the specified version number, up to the next major version number, will work for your project. So in the case of our project any version of Express that is numbered with a major version of “4” will work. So even if my project starts out using, say, Express 4.2.0, if later on there is an Express 4.3.9, my project will use it. However, if and when Express 5.0 is released, my project will never use that.

Create Main App File

The main application file is the one that will be used to start up the application. As you saw above, this will be called index.js. However, since we’re creating everything ourselves this time around you have to make the index.js file. In that file, put the following:

The second and third lines are quite important for our purposes. They require the express module and instantiate Express and assigns my app variable to it. I then use that app instance to set up routes for my home page (“/”) and my about page (“/about”). I also provide a 404 page in case something is requested that could not be found, although I’m using a different route mechanism: instead of get(), I provide use(). I’ll explain that difference a bit later.

To start this app/server you will have to do the following:

$ node index.js

What about the npm start that I showed earlier? That worked because of how the Express scaffold actually generated your project. If you go back to that first package.json file, you’ll see this:

You can feel free to put that in to the current project or just start everything with the node command for the time being.

If you went through the second post in this series, you’ll basically see we’ve taken my simple web app example from there and put it in the context of Express. You can go to these URLs:

Those are the same URLs we worked with in the previous post and you should find they are still working here. So let’s talk about what we did in this file.

Here the app.get is the method used to add routes. Here the “get” corresponds to the HTTP GET verb that is used to get resources from a remote server. The get() method takes two parameters: a path and a function. The path is what defines the route. The function provided is what gets invoked when the route is matched. The parameters passed to that function are the request and response objects. Again, all of this is exactly what you saw in the last post, save we’re now using the app.get() method.

Do note that we are getting a little benefit. For example, in my previous post you had to put in some logic to handle the trailing slash (if any) on a URL as well as account for any possible query strings. Here Express is handling that for you automatically.

As with my initial examples, here I’m returning plain text with a status code of 200. I don’t specify the 200 but Express defaults to that unless you specify a different status code, as I did with the 404 route handler.

A different you might note from the previous examples is that I’m no longer using the res.end() method. Instead, I’m using res.send(), which is provided by Express. Among other things, behind the scenes res.send() actually calls res.end() for you. Instead of calling just res.writeHead() as I did before, I’m now calling two separate methods: res.type() and res.status().

I mentioned that the app.use() method is used for the 404. The app.get() route handler is basically a type of “middleware” that handles a specfic HTTP verb, in this case the GET verb. Likewise if I were to use the app.post() method that would be handling the specific HTTP verb called POST.). The use() method is a different kind of “middleware” that can be thought of as a route handler that handles all HTTP verbs or serves as a catch-all handler for anything that does not get matched by a particular route. I’m simplifying quite a bit here, but I just wanted to give you a flavor of why there is a difference.

Serve Actual HTML via Express Routes

As a final action in this post, let’s make our routes return actual HTML as we did with the examples in the previous post. Express relies on a middleware to handle static files and views. The static middleware allows you to designate one or more directories as containing static resources that are simply to be delivered to the client without any special handling. There are various and sundry ways to do this. The simplest would be to change your index.js file like this:

This will require you creating a public directory and the files home.html, about.html and 404.html.

This is not necessarily a recommended way of doing things but, as you can see, it does work. What res.sendFile() does is act as a more specific variation of res.send(). The sendFile() method automatically sets the content-type response header based on the extension of the filename. This is basically getting around a lot of the middleware and, in fact, if serving static HTML like this is all you want to do you really don’t need Express, which you saw in my second post.

The more standard way to do this same activity in Express is to actually render the HTML. This brings up the concept of a view. A view is basically whatever gets delivered to the client. In the case of a browser that’s usually going to be HTML but it can be an image or various other types of resources. In order to render views with Express, you have to understand that Express supports many different view engines. Express gives some preference to a view engine called Jade. Jade is actually what’s known as a templating engine. These are abstractions that allow to type in a modified form of markup that is then run through an engine which converts the abstracted markup into HTML.

So the upshot here is that Jade doesn’t recognize standard HTML. Yet that’s what I want to serve. Yet Express forces me to use a template engine. So let’s consider the simplest way I can have what I want while still conforming to what Express demands. First, in order to use Jade, you have to install it locally:

$ npm install --save jade

By default, engines like Jade expect to find pages in a directory called “views”. Here, however, I’m going to change that setting so that the ‘views’ directory as set to be the ‘public’ directory that I have already created. Further, I have to tell Jade that it should respond to documents with a ‘.html’ extension. Here is a modified file:

Note you might see some tutorials that have line 9 reading as app.register() but in Express 3 and up that was changed to app.engine(). What this logic does is tell my application that I want to use Jade to render files and it should recognize any files with a .html extension. This is necessary because by default Jade will only process files that have the extension .jade. Finally, notice that in my routes I’m now using the render() method to call up the specific pages.

All of this just barely scratches the surface. There’s a lot more to understand about templating engines as well as the concept of layouts, which allow you to provide common markup in one file that all of your other markup files reference. Yet what I hope you can see is that we were able to take the examples from my previous post and put them in the context of Express.

You may be wondering at this point what any of this has to do with “tester stories.” Well, ultimately, you may end testing apps that are written in JavaScript and running on Node.js. In the next post I’ll get into that a bit.


This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.