Express Web Application Development
上QQ阅读APP看书,第一时间看更新

Your first Express app

The best way to learn any new technology is to try it out using some practical examples. So, let's go ahead and build an Express app and find out how it works.

To ensure our experiments do not mess up our filesystem, let's create a directory named express-app in your home directory and build our app there:

$ cd ~
$ mkdir express-app
$ cd express-app

The app directory is ready and we can start building our first Express app.

The Express manifest file

In Chapter 1, What is Express?, we learned that Express apps are actually Node modules, which means our app also would need a manifest file. So, create a file named package.json in the app directory.

The package.json file can have more than a dozen fields, but for the sake for brevity, let's keep it minimal. Here is what it should look like:

{
  "name": "test-app",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app"
  },
  "dependencies": {
    "express": "3.2.6",
    "jade": "*"
  }
}

The fields used in the manifest file are explained in the following table:

Note

For an interactive guide to all the possible fields in a package.json file, visit http://package.json.nodejitsu.com/.

We have the manifest file ready now. Executing the npm install command in the directory will install all the dependencies in the directory:

$ npm install

You will see a huge wall of scrolling text, that's the dependencies being installed. Once it's done, you will find a new directory named node_modules in the directory; that's where all the dependencies are installed. Because the directory is created and its contents generated by the npm install command, you can safely delete this directory any time you need to for whatever reason, and regenerate it using the same command.

With the dependencies installed, we are now ready to start building out first Express app—from scratch.

Note

Each Express app hosts its own copy of Express framework in a directory named express, under the node_modules directory. You can safely play around with the framework files without affecting other apps. If you ever mess something up, just reinstall it by running npm install in the app directory.

A very basic Express app

Let's create a very basic Express app to get us started. Create a file called app.js and put the following code in it:

// Include the Node HTTP library
var http = require('http');
// Include the Express module
var express = require('express');
// Create an instance of Express
var app = express();

// Start the app
http.createServer(app).listen(3000, function() {
  console.log('Express app started');
});

// A route for the home page
app.get('/', function(req, res) {
  res.send('Welcome!');
});

The app will listen on port 3000 and will have a very limited functionality. It will print "Welcome" when you load its home page, and return a 404 error for all other requests.

Note

HTTP 404 and 500 error handling is built into the router middleware. The details about customizing these error handlers are covered in Chapter 4, Response from the Server.

You might have noticed that the route in the app is defined after the code for starting the server, but it works anyway. Isn't it shocking that it should even work?

The reason it works is because routes are defined on the app object, which is passed to the HTTP API as a reference—any time you make a change on the app object, it is reflected on the server.

Logically, it makes sense to defined the route first and then pass the app object to the HTTP API, but I did afterwards to disruptively bring it to your attention about how the app object is passed to the HTTP API—it is passed as a reference and its methods and properties can be accessed any time. Routes can be defined dynamically, but once defined cannot be redefined.

So much for its being the most important middleware; router wasn't even mentioned in the app. So how does this app work at all?

The mere definition of a route implicitly adds the router middleware at that point of the middleware stack. This feature might be acceptable in simple apps like ours, but in more complex apps, you will need to include the router middleware explicitly, to ensure the proper order of middlewares in the stack. You will learn more about Express middleware in an upcoming section.

Starting and stopping the app

Since Express apps are Node programs, starting an Express app is similar to executing a Node program. In our case, the program resides in a file named app.js, so this is how you will start the server:

$ node app
> Express app started

To stop the server, press Ctrl + C.

Analyzing the output

Start the app and load http://localhost:3000 on your browser to see the output:

If you view the source of the web page and you will find that the server has sent the response in plain text.

How about sending some HTML in the response?

To send HTML response, just change res.send('Welcome!') to res.send('<h1>Welcome!</h1>'), and restart the server. Refresh the page to see the HTML formatted text, as shown in the following screenshot:

Note

For the changes made in application files to reflect, you need to restart the server. This can be a tedious process; you can make it easier for yourself by using supervisor, a Node module that will watch the application files and restart the server when any one of them changes. You can learn more about supervisor at https://github.com/isaacs/node-supervisor.

Now, how do we send a whole HTML page?

Express apps have a special component called views, wherein you write the necessary HTML using a templating language, which helps in separating HTML from the core app. Also, any changes made in the views will be reflected in the HTML output without requiring the server to be restarted.

Express app with views

Let's rewrite the app to use views. The view files can reside in any conveniently named directory on the filesystem, but it makes sense to have it right in the application directory.

So, let go ahead and create a directory for our views, named views:

$ mkdir views

Now create two view files in the views directory: one named index.jade for the home page, another named hello.jade for the hello web page.

The first thing you might notice about the view files is that they have the .jade extension. This unfamiliar extension might make it look a little intimidating, but you will discover that it is very intuitive once you start using it.

Note

Note that Jade is just one of the many templating languages that is supported by Express. It is not mandatory to use Jade with Express. However, we focus on it especially because it was created keeping Express in mind, and is a natural fit for it. If you want to learn more about Jade, you can take a quick look at Chapter 5, The Jade Templating Language.

Express supports all templating languages that work with Node. It is just a matter of installing the right module and configuring your app to use it.

Let's familiarize ourselves with Jade by creating the content of the view files:

Here is the content for index.jade:

html
  head
      title Welcome
  body Welcome!

And here is the content for hello.jade:

html
  head
    title Hello
  body
    b Hello!

As you can notice, indentation is the key in Jade. You use consistent space- or tab-based indentations to nest HTML elements. We don't need to use the overly verbose HTML opening and closing tags. There is much more to Jade than this, but for now, you should be good to go with it. You will learn more about Jade in Chapter 5, The Jade Templating Language.

Tip

Make sure to consistently use spaces or tabs for indentation, or else Jade will throw an error.

Let's update app.js to use our newly created views. The following code is commented well to help you understand what each relevant line of code is doing:

var http = require('http');
var express = require('express');
var app = express();

// Set the view engine
app.set('view engine', 'jade');
// Where to find the view files
app.set('views', './views');

// A route for the home page - will render a view
app.get('/', function(req, res) {
  res.render('index');
});

// A route for /say-hello - will render a view
app.get('/say-hello', function(req, res) {
  res.render('hello');
});

app.get('/test', function(req, res) {
  res.send('this is a test');
});

http.createServer(app).listen(3000, function() {
  console.log('App started');
});

In the updated app.js, we have declared that we will be using the Jade templating engine, and have specified the views directory for Jade. You can see we are using res.render() for two of the routes to render views.

For a matched route, res.render() will look for the view in the views directory and render it accordingly

Restart the server and load http://localhost:3000, http://localhost:3000/say-hello, and http://localhost:3000/test in the browser to see the new additions made to the app.

If you view the source of these web pages, you will find that the ones using views have generated complete HTML.

Make some changes in the view files and refresh the browser to see the changes. You don't need to restart the app to see the changes made in the view files, they are reflected instantly when you refresh the browser.

So far you have only seen a preview of Jade, you will learn much more in Chapter 5, The Jade Templating Language. Till then, let's continue understanding an Express app better.

A public directory for the app

We are now quite close to having a fully functional website, albeit a simple one. What remain now are CSS, JavaScript, images, and other files for the app. Where do we keep these files?

Express has a middleware called static, using which we can mark a directory in the filesystem for serving static files for the app. Any file kept in these directories can be directly accessed via the browser.

This is how you use the static middleware to set a directory for static resources:

app.use(express.static('./public'));

It is worth noting that you can set multiple static directories, if you need to:

app.use(express.static('./public'));
app.use(express.static('./files'));
app.use(express.static('./downloads'));

Let's create a static directory named public and use it for our static content:

$ mkdir public
$ mkdir public/images
$ mkdir public/javascripts
$ mkdir public/stylesheets

These directory names are chosen by convention, you can name them anything you want; as long as the static directory is set, they will work as expected. However, it is a good idea to stick to what I suggested, because those names are very commonly used by web developers around the world.

Create a nice looking image named logo.png and keep it in the images directory. I am using the following Packt logo:

Create a file named main.js in the javascripts directory with the following content:

window.onload = function() {
  document.getElementById('smile').innerHTML = ':)';
};

Create a file named style.css in the stylesheets directory with the following content:

#content {
  width: 220px;
  margin: 0 auto;
  text-align: center;
  border: 1px solid #ccc;
  box-shadow: 0 3px 4px #ccc;
  padding: 5px;
}

Update index.jade to include the newly added files:

html
  head
    title Welcome
    script(src='javascripts/main.js')
    link(rel='stylesheet', href='stylesheets/style.css')
  body
    #content
      img(src='images/logo.png')
      p WELCOME
      #smile

Update app.js to set a static directory:

var http = require('http');
var express = require('express');
var app = express();

app.set('view engine', 'jade');
app.set('views', './views');

// Mark the public dir as a static dir
app.use(express.static('./public'));

app.get('/', function(req, res) {
  res.render('index');
});

http.createServer(app).listen(3000, function() {
  console.log('App started');
});

Restart the app and load the home page:

Congrats! Your first full-fledged Express app is up and running.