justjs: node.js tutorials

New here? You might want to start at the beginning.

5/16 '12

Now That's REALLY Basic: The Simplest Blog Ever

And It Really Does Something!

For our very first node app, we'll create the simplest blog ever. And I do mean simple! There's no database, no layout, no stylesheet, no template language to make it easier to render things... and all of that will change in later examples. But for now, this is a great way to explore the basics of creating a web app in Node, without resorting to a meaningless "Hello World" application. I really hate those.

To get started, create a folder inside your home directory called "node-apps", create a second direcory inside that called "blog-1", and finally create a new text file there called "server.js". And if you want, cheat: pop over to github to copy and paste the code. Or just follow along as I explain.

By convention, Node applications begin life in a file called server.js and starts executing at the top of the file. And the first thing we usually do in a Node application is pull in a few other JavaScript files that do useful things. 

Unlike PHP, Node isn't already baked into a webserver like Apache. Instead, every node web application is a webserver, listening for connections from web browsers on its very own port. So the first thing we'll do is summon a module that implements the HTTP protocol for us. (HTTP, of course, is the protocol that web browsers and servers speak to one another.) Here's that first line:

var http = require('http');
This line finds the http module that came with Node, executes that code, and returns an object with lots of useful functions for us. We'll learn how to write our own modules later; it's a great way to organize and share code.
 
We're almost ready to create our webserver. But first, before we can have a blog, we need some posts to share on that blog. Later we'll fetch them from MongoDB, but for this first example, let's just create a little bit of data right in server.js:
var posts = {
  '/welcome-to-my-blog': {
    title: 'Welcome to my blog!',
    body: 'I am so glad you came.'
  },

  '/i-am-concerned-about-stuff': {
    title: 'I am concerned about stuff!',
    body: 'People need to be more careful with stuff.'
  },

  '/i-often-dream-of-trains': {
    title: 'I often dream of trains.',
    body: "I often dream of trains when I'm alone."
  }
};
We've created an object and assigned it to the posts variable. Each post is a property of the object, and the name of the property is the URL or "slug" of the individual post, a nice friendly URL based on the title. Every post gets its own friendly link. (Later on we'll see how to generate these automatically and make sure they are unique.)
 
Each post, in turn, is an object as well, with title and body properties. This gives us a convenient set of data to play with.
 
Enough prologue- let's make a webserver!
var server = http.createServer(function(req, res) { ... code goes here ... } );
The createServer function creates a webserver. The createServer function expects one function as its argument. In this case I've chosen to define the function right inside the parentheses. If I wanted, I could just give the name of another function that resides elsewhere.

Functional Programming and Node

"Hang on, a function wants me to give another function to it?" Yep! Those of you who have programmed with jQuery are nodding along with me. Those who have not might be a little confused.
 
JavaScript is a functional programming language. That means we can define a function just about anywhere. And we can assign functions to variables and even pass them to other functions, just like any other data. 
 
Node, like jQuery, takes advantage of this in a big way. Almost all important functions in Node accept a "callback function" to be called when something is ready, complete, broken, on fire, or otherwise in need of attention. And until one of those things happens, Node just keeps on trucking - delivering content you already queued up to be sent, accepting more connections, and calling other callback functions elsewhere in your code. 
 
Node and jQuery share another important trait: neither one of them ever, ever, ever makes the user wait for JavaScript code to finish running. All JavaScript programmers soon discover what happens if your code takes a long time to run: the user can't do anything at all with that webpage until your code finishes. Eventually the web browser pops up a dialog box that says something like:
 
"This webpage really stinks. Do you want to make the pain stop?"
 
You don't want to be that guy (or gal, depending). So you learn quickly to use features like window.setTimeout() to do things in small portions, a little at a time. And you also learn to create functions that respond to events, like this slightly contrived jQuery example:
// Turn the background green when the user clicks a certain link
$('#my-link').click(function() { $('body').css('background-color', 'green'); });
These are healthy habits you probably already have, and they will serve you well with Node too.
 
Let's take a look at our callback function: the code between the curlies that responds to each request.
 
The callback function takes two arguments: req and res. req (short for "request") represents what the web browser asked us for, and contains important stuff like req.url. res (short for "response") is our response to the web browser.
 
And here it is (mostly):
function(req, res) {
  if (req.url === '/')
  {
    // Deliver a list of posts
    index();
  }
  else if (posts[req.url])
  {
    // Deliver this particular post
    post(req.url);
  }
  else
  {
    notFound();
  }
  ... Nested functions go here ...
}
This code looks at req.url to figure out what the user wants. 
 
Did they ask for the home page ("/") of the site? Then we call index() to deliver it.
 
Did they ask for an individual post? Then we check whether there is a post with that URL, and then we call post(req.url) to deliver it. All we have to do is check whether posts[req.url] exists. 
 
Did they ask for something ridiculous? Then we call notFound() to break the bad news gently.

Nested Functions

So far, so good. But where are the individual functions like index()? They are nested right inside the callback function.
 
"Whoa there, I can put functions inside functions?" Oh, yes. This feature is common to all functional programming languages, and notably absent from a number of other languages. It has many benefits. One of the most important is that your nested functions can "see" variables that are defined in the outer, enclosing function. Like the "req" and "res" variables. 

Here's the index() function that renders the home page of the blog, with links to all the posts:

 

  function index()
  {
    var s = "<title>My Blog</title>\n";
    s += "<h1>My Blog</h1>\n";
    s += "<ul>\n";
    for (var slug in posts)
    {
      var post = posts[slug];
      s += '<li><a href="' + slug + '">' + post.title + '</a></li>' + "\n";
    }
    s += "</ul>\n";
    sendBody(s);
  }
All this function really does is build a big string, 's', that contains the HTML of the home page. By adding to this string we build up the markup for the page. First the title and heading, then an opening 'ul' list tag, and then the 'li' tags and links for the individual posts.
 
This line loops over the slugs (URLs) of the individual posts in the posts object:
for (var slug in posts) { ... }
Then we can access each individual post object as posts[slug] in order to build up a list of links.
 
"Hey, isn't this a tedious way to build HTML?" Sure. I've seen worse, but it's not much fun to maintain this way. Fortunately there are alternatives, and we'll use them. In an upcoming post we'll look at Underscore templates, a great way to have our JavaScript cake and convenient templates, too. But at the end of the day, we're still building a response to send to the user. So in this post I'm emphasizing that simple idea.

Responding to the User

Once we have the entire page in 's', we're ready to send it to the browser. Since we do this more than once, I've written a function for it. Let's look at the sendBody function:
  function sendBody(s)
  {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(s);
  }
This function does two things: it sets up the headers of our HTTP response, and it asks Node to send the actual content.
 
This line tells Node what the HTTP status code will be, and what the content type of the response will be. We want status code 200 ("OK"), and the content type text/html (as opposed to text/plain, image/gif, et cetera):
    res.writeHead(200, {'Content-Type': 'text/html'});
Then we ask Node to send the body of the page:
    res.end(s);
Notice I said "ask Node to send the body of the page." I did not say "send the body of the page right this instant." Node will take the HTML off our hands and then start delivering it in the background until the browser accepts it all, then politely say goodbye to the browser, without further help from us. But Node does all this "in between" future callbacks to our code. While we're delivering responses for other URLs for other users, Node might still be sending our page to the first user.
 
Does that matter? It does if our code tries to do something slow! That's why when we do potentially slow things, like requesting data from a database, we'll always do it with a callback function that gets called when the operation is done... allowing Node to keep muscling along while it waits for the database to get back to us. That's why you can expect to see lots of callback functions. Fortunately, in a functional language like JavaScript, using callbacks quickly becomes friendly and intuitive.

Delivering a Post

Let's take a quick peek at the post() function. This is similar to index():
  function post(url)
  {
    var post = posts[url];
    var s = "<title>" + post.title + "</title>\n";
    s += "<h1>My Blog</h1>\n";
    s += "<h2>" + post.title + "</h2>\n";
    s += post.body;
    sendBody(s);
  }
Our post() function takes a url as an argument, and builds a page much like index() does, after first fetching the appropriate post from the posts object. And we reuse the sendBody() function to ask Node to deliver it to the browser.

Breaking Bad (News)

All well and good. But what happens when the browser asks for a post that doesn't exist? Enter the notFound() function:
  function notFound()
  {
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end('<h1>Post not found.</h1>');
  }
Sending a "404 not found" error isn't much different from sending a successful response. We can still call res.end() to deliver the text of the response. We just need to send status code 404 (Not Found) instead of 200 (OK).

Listening For Connections

We're finished- almost! We've created the server and provided a callback to handle requests from web browsers. But we haven't actually told Node to start accepting those connections yet.

Here's the call to start accepting connections on port 3000:

 

server.listen(3000);
And we'll send a message to the console (the terminal window, on our Mac) to make it obvious that the server is ready:
console.log("Listening for connections");

Starting Up Our Server

We have a complete web application! All we have to do now is start it up.
 
To launch your blog, first open a Terminal window. Then use the cd command to switch to the directory where you've put it:
cd node-apps/blog-1
Now use the ls command to list the files here. You should see your server.js file:
Macintosh-5:blog-1 boutell$ ls

server.js
You're ready to start your web app! Just type:
node server.js
You should see:
Listening for connections
Leave the app running in the Terminal window for now and visit it with your web browser. Just visit http://localhost:3000/ to see your blog's index page. You can click through to individual posts, or visit the URL of a nonexistent post to see the 404 error message.
 
When you're through playing with the app, you can shut it down by going to the terminal window and pressing Control-C to return to the terminal prompt. After that, you can get back to the node-apps folder by typing:
cd ..
And then:
ls
To list your app and any other folders you've created for node apps. 

Things Just Get Easier (And Cooler) From Here

We've built our first node app! But we did it the hard way, a little bit. I wanted to be sure to give you a sense of how Node really works. Next I'll introduce modules that do some of the hard work for you, making it a lot easier to respond to different URLs and send back nicely templated webpages with more complete markup. Then we'll start storing our blog posts in a real database so we can create, edit and delete them... and so on from there, until we achieve total world domination together. Isn't that heartwarming?

 

blog comments powered by Disqus