First Steps in Code

This section will take you through a basic Node program before we move on to more in-depth programs.

Node REPL

One of the things that’s often hard to understand about Node.js is that, in addition to being a server, it’s also a runtime environment in the same way that Perl, Python, and Ruby are. So, even though we often refer to Node.js as “server-side JavaScript,” that doesn’t really accurately describe what Node.js does. One of the best ways to come to grips with Node.js is to use Node REPL (“Read-Evaluate-Print-Loop”), an interactive Node.js programming environment. It’s great for testing out and learning about Node.js. You can try out any of the snippets in this book using Node REPL. In addition, because Node is a wrapper around V8, Node REPL is an ideal place to easily try out JavaScript. However, when you want to run a Node program, you can use your favorite text editor, save it in a file, and simply run node filename.js. REPL is a great learning and exploration tool, but we don’t use it for production code.

Let’s launch Node REPL and try out a few bits of JavaScript to warm up (Example 1-6). Open up a console on your system. I’m using a Mac with a custom command prompt, so your system might look a little different, but the commands should be the same.

Example 1-6. Starting Node REPL and trying some JavaScript

$Enki:~ $ node
> 3 > 2 > 1
false
> true == 1
true
> true === 1
false

Note

The first line, which evaluates to false, is from http://wtfjs.com, a collection of weird and amusing things about JavaScript.

Having a live programming environment is a really great learning tool, but you should know a few helpful features of Node REPL to make the most of it. It offers meta-commands, which all start with a period (.). Thus, .help shows the help menu, .clear clears the current context, and .exit quits Node REPL (see Example 1-7). The most useful command is .clear, which wipes out any variables or closures you have in memory without the need to restart REPL.

Example 1-7. Using the metafeatures in Node REPL

> console.log('Hello World');
Hello World
> .help
.clear  Break, and also clear the local context.
.exit   Exit the prompt
.help   Show repl options
> .clear
Clearing context...
> .exit
Enki:~ $

When using REPL, simply typing the name of a variable will enumerate it in the shell. Node tries to do this intelligently so a complex object won’t just be represented as a simple Object, but through a description that reflects what’s in the object (Example 1-8). The main exception to this involves functions. It’s not that REPL doesn’t have a way to enumerate functions; it’s that functions have the tendency to be very large. If REPL enumerated functions, a lot of output could scroll by.

Example 1-8. Setting and enumerating objects with REPL

Enki:~ $ node
> myObj = {};
{}
> myObj.list = ["a", "b", "c"];
[ 'a', 'b', 'c' ]
> myObj.doThat = function(first, second, third) { console.log(first); };
[Function]
> myObj
{ list: [ 'a', 'b', 'c' ]
, doThat: [Function]
}
>

A First Server

REPL gives us a great tool for learning and experimentation, but the main application of Node.js is as a server. One of the specific design goals of Node.js is to provide a highly scalable server environment. This is an area where Node differs from V8, which was described at the beginning of this chapter. Although the V8 runtime is used in Node.js to interpret the JavaScript, Node.js also uses a number of highly optimized libraries to make the server efficient. In particular, the HTTP module was written from scratch in C to provide a very fast nonblocking implementation of HTTP. Let’s take a look at the canonical Node “Hello World” example using an HTTP server (Example 1-9).

Example 1-9. A Hello World Node.js web server

var http = require('http'); 
http.createServer(function (req, res) { 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.end('Hello World\n'); 
}).listen(8124, "127.0.0.1"); 
console.log('Server running at http://127.0.0.1:8124/');

The first thing that this code does is use require to include the HTTP library into the program. This concept is used in many languages, but Node uses the CommonJS module format, which we’ll talk about more in Chapter 8. The main thing to know at this point is that the functionality in the HTTP library is now assigned to the http object.

Next, we need an HTTP server. Unlike some languages, such as PHP, that run inside a server such as Apache, Node itself acts as the web server. However, that also means we have to create it. The next line calls a factory method from the HTTP module that creates new HTTP servers. The new HTTP server isn’t assigned to a variable; it’s simply going to be an anonymous object in the global scope. Instead, we use chaining to initialize the server and tell it to listen on port 8124.

When calling createServer, we passed an anonymous function as an argument. This function is attached to the new server’s event listener for the request event. Events are central to both JavaScript and Node. In this case, whenever there is a new request to the web server, it will call the method we’ve passed to deal with the request. We call these kinds of methods callbacks because whenever an event happens, we “call back” all the methods listening for that event.

Perhaps a good analogy would be ordering a book from a bookshop. When your book is in stock, they call back to let you know you can come and collect it. This specific callback takes the arguments req for the request object and res for the response object.

Inside the function we created for the callback, we call a couple of methods on the res object. These calls modify the response. Example 1-9 doesn’t use the request, but typically you would use both the request and response objects.

The first thing we must do is set the HTTP response header. We can’t send any actual response to the client without it. The res.writeHead method does this. We set the value to 200 (for the HTTP status code “200 OK”) and pass a list of HTTP headers. In this case, the only header we specify is Content-type.

After we’ve written the HTTP header to the client, we can write the HTTP body. In this case, we use a single method to both write the body and close the connection. The end method closes the HTTP connection, but since we also passed it a string, it will send that to the client before it closes the connection.

Finally, the last line of our example uses the console.log. This simply prints information to stdout, much like the browser counterpart supported by Firebug and Web Inspector.

Let’s run this with Node.js on the console and see what we get (Example 1-10).

Example 1-10. Running the Hello World example

Enki:~ $ node
> var http = require('http'); 
> http.createServer(function (req, res) { 
...     res.writeHead(200, {'Content-Type': 'text/plain'}); 
...     res.end('Hello World\n'); 
...   }).listen(8124, "127.0.0.1"); 
> console.log('Server running at http://127.0.0.1:8124/'); 
Server running at http://127.0.0.1:8124/ 
node>

Here we start a Node REPL and type in the code from the sample (we’ll forgive you for pasting it from the website). Node REPL accepts the code, using ... to indicate that you haven’t completed the statement and should continue entering it. When we run the console.log line, Node REPL prints out Server running at http://127.0.0.1:8124/. Now we are ready to call our Hello World example in a web browser (Figure 1-1).

Viewing the Hello World web server from a browser

Figure 1-1. Viewing the Hello World web server from a browser

It works! Although this isn’t exactly a stunning demo, it is notable that we got Hello World working in six lines of code. Not that we would recommend that style of coding, but we are starting to get somewhere. In the next chapter, we’ll look at a lot more code, but first let’s think about why Node is how it is.

Get Node: Up and Running now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.