Learning Server-Side JavaScript with Node.js

Learning Server-Side JavaScript with Node.js

Tutorial Details
  • Technology: JavaScript
  • Difficulty: Intermediate-Advanced

Node.js is all the buzz at the moment, and makes creating high performance, real-time web applications easy. It allows JavaScript to be used end to end, both on the server and on the client. This tutorial will walk you through the installation of Node and your first “Hello World” program, to building a scalable streaming Twitter server.

What is Node.js?

JavaScript has traditionally only run in the web browser, but recently there has been considerable interest in bringing it to the server side as well, thanks to the CommonJS project. Other server-side JavaScript environments include Jaxer and Narwhal. However, Node.js is a bit different from these solutions, because it is event-based rather than thread based. Web servers like Apache that are used to serve PHP and other CGI scripts are thread based because they spawn a system thread for every incoming request. While this is fine for many applications, the thread based model does not scale well with many long-lived connections like you would need in order to serve real-time applications like Friendfeed or Google Wave.

“Every I/O operation in Node.js is asynchronous…”

Node.js, uses an event loop instead of threads, and is able to scale to millions of concurrent connections. It takes advantage of the fact that servers spend most of their time waiting for I/O operations, like reading a file from a hard drive, accessing an external web service or waiting for a file to finish being uploaded, because these operations are much slower than in memory operations. Every I/O operation in Node.js is asynchronous, meaning that the server can continue to process incoming requests while the I/O operation is taking place. JavaScript is extremely well suited to event-based programming because it has anonymous functions and closures which make defining inline callbacks a cinch, and JavaScript developers already know how to program in this way. This event-based model makes Node.js very fast, and makes scaling real-time applications very easy.


Step 1 Installation

Node.js runs on Unix based systems, such as Mac OS X, Linux, and FreeBSD. Unfortunately, Windows is not yet supported, so if you are a Windows user, you can install it on Ubuntu Linux using Virtualbox. To do so, follow this tutorial. You will need to use the terminal to install and run Node.js.

  1. Download the latest release of Node.js from nodejs.org (the latest version at the time of this writing is 0.1.31) and unzip it.
  2. Open the terminal, and run the following commands.
    cd /path/to/nodejs
    make
    sudo make install
    		

    A lot of messages will be outputted to the terminal as Node.js is compiled and installed.


Step 2 Hello World!

Every new technology starts with a “Hello World!” tutorial, so we will create a simple HTTP server that serves up that message. First, however, you have to understand the Node.js module system. In Node, functionality is encapsulated in modules which must be loaded in order to be used. There are many modules listed in the Node.js documentation. You load these modules by using the require function like so:

var sys = require("sys");

This loads the sys module, which contains functions for dealing with system level tasks like printing output to the terminal. To use a function in a module, you call it on the variable that you stored the module in, in our case sys.

sys.puts("Hello World!");

Running these two lines is as simple as running the node command with the filename of the javascript file as an argument.

node test.js

This will output “Hello World!” to the command line when run.

To create an HTTP server, you must require the http module.

var sys = require("sys"),
    http = require("http");
	
http.createServer(function(request, response) {
    response.sendHeader(200, {"Content-Type": "text/html"});
    response.write("Hello World!");
    response.close();
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

This script imports the sys and http modules, and creates an HTTP server. The anonymous function that is passed into http.createServer will be called whenever a request comes in to the server. Once the server is created, it is told to listen on port 8080. When a request to the server comes in, we first send HTTP headers with the content type and status code of 200 (successful). Then we send “Hello World!” and close the connection. You might notice that we have to explicitly close the connection. This will make it very easy to stream data to the client without closing the connection. If you run this script and go to http://localhost:8080/ in your browser, you will see “Hello World!”


Step 3 A Simple Static File Server

OK, so we have built an HTTP server, but it doesn’t send anything except for “Hello World,” no matter what URL you go to. Any HTTP server must be able to send static files such as HTML files, images and other files. The following code does just that:

var sys = require("sys"),
    http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs");
	
http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
    	if(!exists) {
    		response.sendHeader(404, {"Content-Type": "text/plain"});
    		response.write("404 Not Found\n");
    		response.close();
    		return;
    	}
    	
    	fs.readFile(filename, "binary", function(err, file) {
    		if(err) {
    			response.sendHeader(500, {"Content-Type": "text/plain"});
    			response.write(err + "\n");
    			response.close();
    			return;
    		}
    		
    		response.sendHeader(200);
    		response.write(file, "binary");
    		response.close();
    	});
    });
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

We start by requiring all of the modules that we will need in our code. This includes the sys, http, url, path, and fs or filesystem modules. Next we create an HTTP server like we did before. This time, we will use the url module to parse the incoming URL of the request and find the pathname of the file being accessed. We find the actual filename on the server’s hard drive by using path.join, which joins process.cwd(), or the current working directory, with the path to the file being requested. Next, we check if the file exists, which is an asynchronous operation and thus requires a callback. If the file does not exist, a 404 Not Found message is sent to the user and the function returns. Otherwise, we read the file using the fs module using the “binary” encoding, and send the file to the user. If there is an error reading the file, we present the error message to the user, and close the connection. Because all of this is asynchronous, the server is able to serve other requests while reading the file from the disk no matter how large it is.

If you run this example, and navigate to http://localhost:8080/path/to/file, that file will be shown in your browser.


Step 4 A Real Time Tweet Streamer

Building on our static file server, we will build a server in Node.js that streams tweets to a client that is served through our static file server. To start, we will need one extra module in this example: the events module. Node has a concept called an EventEmitter, which is used all over to handle event listeners for asynchronous tasks. Much like in jQuery or another client side JavaScript framework where you bind event listeners to things like mouse clicks, and AJAX requests, Node allows you to bind event listeners to many things, some of which we have already used. These include every I/O operation, such as reading a file, writing a file, checking if a file exists, waiting for HTTP requests, etc. The EventEmitter abstracts the logic of binding, unbinding, and triggering such event listeners. We will be using an EventEmitter to notify listeners when new tweets are loaded. The first few lines of our tweet streamer imports all of the required modules, and defines a function for handling static files, which was taken from our previous example.

var sys = require("sys"),
    http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    events = require("events");

function load_static_file(uri, response) {
	var filename = path.join(process.cwd(), uri);
	path.exists(filename, function(exists) {
		if(!exists) {
			response.sendHeader(404, {"Content-Type": "text/plain"});
			response.write("404 Not Found\n");
			response.close();
			return;
		}
		
		fs.readFile(filename, "binary", function(err, file) {
			if(err) {
				response.sendHeader(500, {"Content-Type": "text/plain"});
				response.write(err + "\n");
				response.close();
				return;
			}
			
			response.sendHeader(200);
			response.write(file, "binary");
			response.close();
		});
	});
}

We have used the http module to create a server before, but it is also possible to create an HTTP client using the module. We will be creating an HTTP client to load tweets from Twitter’s public timeline, which is performed by the get_tweets function.

var twitter_client = http.createClient(80, "api.twitter.com");

var tweet_emitter = new events.EventEmitter();

function get_tweets() {
	var request = twitter_client.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
	
	request.addListener("response", function(response) {
		var body = "";
		response.addListener("data", function(data) {
			body += data;
		});
		
		response.addListener("end", function() {
			var tweets = JSON.parse(body);
			if(tweets.length > 0) {
				tweet_emitter.emit("tweets", tweets);
			}
		});
	});
	
	request.close();
}

setInterval(get_tweets, 5000);

First, we create an HTTP client on port 80 to api.twitter.com, and create a new EventEmitter. The get_tweets function creates an HTTP “GET” request to Twitter’s public timeline, and adds an event listener that will be triggered when Twitter’s servers respond. Because Node.js is asynchronous, the data in the body of the response comes in chunks, which are picked up by the response’s “data” listener. This listener simply appends the chunk to the body variable. Once all of the chunks have come in, the “end” listener is triggered, and we parse the incoming JSON data. If more than one tweet is returned, we emit the “tweets” event on our tweet_emitter, and pass in the array of new tweets. This will trigger all of the event listeners listening for the “tweets” event, and send the new tweets to each client. We retreive the new tweets every five seconds, by using setInterval.

Finally, we need to create the HTTP server to handle requests.

http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    if(uri === "/stream") {
    
    	var listener = tweet_emitter.addListener("tweets", function(tweets) {
    		response.sendHeader(200, { "Content-Type" : "text/plain" });
    		response.write(JSON.stringify(tweets));
    		response.close();
    		
    		clearTimeout(timeout);
    	});
    	
    	var timeout = setTimeout(function() {
    		response.sendHeader(200, { "Content-Type" : "text/plain" });
    		response.write(JSON.stringify([]));
    		response.close();
    		
    		tweet_emitter.removeListener(listener);
    	}, 10000);
    	
    }
    else {
    	load_static_file(uri, response);
    }
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

Just as we did with our static file server, we create an HTTP server that listens on port 8080. We parse the requested URL, and if the URL is equal to "/stream", we will handle it, otherwise we pass the request off to our static file server. Streaming consists of creating a listener to listen for new tweets on our tweet_emitter, which will be triggered by our get_tweets function. We also create a timer to kill requests tht last over 10 seconds by sending them an empty array. When new tweets come in, we send the tweets as JSON data, and clear the timer. You will see how this works better after seeing the client side code, which is below. Save it as test.html in the same directory as the server side JavaScript.

<!DOCTYPE html>
<html>
	<head>
		<title>Tweet Streamer</title>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
	</head>
	<body>
		<ul id="tweets"></ul>
		<script type="text/javascript">
		var tweet_list = $("#tweets");
		
		function load_tweets() {
			$.getJSON("/stream", function(tweets) {
				$.each(tweets, function() {
					$("<li>").html(this.text).prependTo(tweet_list);
				});
				load_tweets();
			});
		}
		
		setTimeout(load_tweets, 1000);
		</script>
	</body>
</html>

Here, we have a simple HTML page that imports the jQuery library and defines an unordered list to put the tweets in. Our client side JavaScript caches the tweet list, and runs the load_tweets function after one second. This gives the browser enough time to finish loading the page before we start the AJAX request to the server. The load_tweets function is very simple: It uses jQuery’s getJSON function to load /stream. When a response comes in, we loop through all of the tweets and prepend them to the tweet list. Then, we call load_tweets again. This effectively creates a loop that loads new tweets, which times out after ten seconds because of the timeout on the server. Whenever there are new tweets, they are pushed to the client which maintains a continuous connection to the server. This technique is called long-polling.

If you run the server using node and go to http://localhost:8080/test.html, you will see the Twitter public timeline stream into your browser.


Next Steps

Node.js is a very exciting technology that makes it easy to create high performance real time applications. I hope you can see its benefit, and can use it in some of your own applications. Because of Node’s great module system, it is easy to use prewritten code in your application, and there are many third party modules available for just about everything – including database connection layers, templating engines, mail clients, and even entire frameworks connecting all of these things together. You can see a complete list of modules on the Node.js wiki, and more Node tutorials can be found on How To Node. I would also recommend that you watch a video from JSConf, in which Ryan Dahl, the creator of Node, describes the design philosophy behind Node. That is available here.

I hope you have enjoyed this tutorial. If you have any comments, you can leave one here or send me a message on Twitter. Happy noding!

Tags: node js
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://codendesign.blogspot.com nXqd

    I wanna tell nodejs is great and it’s gonna be the next step in client-server network programming :)

  • http://dan.cx/ Daniel15

    ” Unfortunately, Windows is not yet supported, so if you are a Windows user, you can install it on Ubuntu Linux using Virtualbox.”
    That’s not correct. Node.js actually works on Windows, you just have to compile it in Cygwin.

    Here’s a screenshot from my PC: http://ss.dan.cx/2010/10/31-10.12.09.png

    • http://www.rouse.ws William Rouse

      Can you point me to a set of instructions to load Cygwin and the tools need to compile and run node.js
      Thanks!

  • http://www.brettwidmann.com Brett Widmann

    This is a very helpful tutorial. Thanks for including the download.

  • praveen

    hi am a beginer in node.js and i tried to impliment the simple static file server in this but getting a segmentation fault in either path.exists() or if its not used in fs.readline() is this because of any installation problem or so ? i tried the same code mentioned here please help me..

  • http://mattmueller.me Matt Mueller

    Thanks for the article – this definitely got me started!

    Unfortunately, the twitter streamer no longer working as of v0.2.5. I’m getting:

    events:81
    throw new Error(‘removeListener only takes instances of Function’);
    ^
    Error: removeListener only takes instances of Function

    Anyone know what’s up with that?

    Thanks!

  • http://www.popularpennies.com Stocker12

    Thanks for the article. I used it to build my own real-time streamer (penny stock news in my case). It’s actually a joy working with node.js. Its one of the first newer technologies that have simply “worked” for me. It allowed me to create a tool that I’ve been looking for (a free one that is) for a long time in a matter of days.

  • http://vortrieb.net/ Nils

    Some of the stuff is already deprecated. But nevertheless this gave me quite a good kickstart to get started with NodeJS. Can’t wait to digg deeper into it. Would love to see more NodeJS tuts of this quality.

  • http://justplay.fm Alex Nimmo

    This is because the event type is not specified. removeListener expects 2 args, the event type and the instance of the function. It is interpreting the single arg ‘listener’ as the event type and complaining that there is no second arg. Change this line for:

    tweet_emitter.removeListener(“tweets”, listener);

    Hope this helps,
    Alex

  • http://none Jordan Christopher

    You have a bug..
    The emitter will push responses to several listeners that are not associated with any active client requests.
    When a request is done (either due to timeout, or pushing tweets to the client), we need to unregister that listener.

    -jcw

  • http://none Jordan Christopher

    Also,

    You only want to emmit once! So use emitter.once, otherwise each tweet batch will fire off several historical emitter handlers that aren’t tied to live requests.

    Each time there will be one more handler..

  • anasanjaria

    I am newbie in node.js and I want to know about it. I have google it but not satisfied. I have found some points regarding node.js
    why use node?
    One reason is efficiency. In a web application, your main response time cost is usually the sum of time it takes to execute all your database queries. With node, you can execute all your queries at once, reducing the response time to the duration it takes to execute the slowest query.But y we execute all of queries at once. ? execution of queries depend on requirement.
    Also node.js is event-based while php etc are thread based. Can u explain thread based ?
    Can u plz guide me?

  • http://www.yi-wang.me Yi Wang
    • bingo

      what a mess

  • http://proudn00b.com Emile Petrone
  • http://en4.me Chu

    I think, that you have the infinity deep recursion inside load_tweets function (test.html)…

  • http://en4.me Chu

    //I’ve tried to stop eth0 when your script is running, and got the
    Error: ECONNREFUSED, Could not contact DNS servers
    //(at the twitter_client.request line)
    //Can you explain me how I can catch this error?

    //I have:
    var request = twitter_client.request(“GET”, “/1/statuses/public_timeline.json”, {“host”: “api.twitter.com”})
    //and tried
    request.addListener(“error”, function() {
    console.log(“Achtung”);
    });
    //but no changes
    //Thanks in advance, I really want to understand node.

  • http://github.com/aaronblohowiak Aaron Blohowiak

    Just helped someone in the node.js irc room to debug an issue with this. In more recent versions of node, you will have to .end() the httpClient request, not .close() it.

  • http://nickwan.wordpress.com Nick

    I tried to do a counter test. Each time I load it advanced by 2, which should be 1.
    Here is the code :

    var sys = require(“sys”),
    http = require(“http”);
    var counter=0;

    http.createServer(function(request, response) {
    counter++;
    response.sendHeader(200, {“Content-Type”: “text/html”});
    response.write(“Hello World!”);
    response.write(“Counter:”+counter);
    response.close();
    }).listen(8080);

    sys.puts(“Server running at http://localhost:8080/“);

    Wondering why is that :p

    • Ferdy

      Probably you browser is doing a request for favicon.ico first, incrementing the counter to 1
      Then for the actual request you will get 2.

  • matt

    TypeError: Object # has no method ‘sendHeader’

    response.sendHeader is now response.writeHead

    http://nodejs.org/docs/v0.4.0/api/http.html#response.write

    • Senad

      Yes, and I think response.close() is now response.end()

  • kuddl

    @nick: I tried to do a counter test. Each time I load it advanced by 2, which should be

    => it’s the favicon.ico the browser tries to fetch. do a console.log(request.url) just before u clode the connection, an u will see

  • http://www.abcarticledirectory.com/Article/The-History-Behind-The-Frisbee/1168264 Danial Finizio

    I’m typically to blogging and i really admire your content. The article has really peaks my interest. I’m going to bookmark your site and preserve checking for brand new information.

  • http://chovy.com chovy

    I get the following error on debian when installing nodejs:

    $ make
    Project not configured (run ‘waf configure’ first)
    make: *** [program] Error 1

    • http://mirohristov.com Miro

      ./configure –without-ssl
      make
      make install

      took me 2 days to figure it out so enjoy :)

      • catape

        Thank you so much! It took me 5 minutes thanks to you and of course, google…

      • http://raphaelddl.com RaphaelDDL

        You saved my life, thank you.

      • Wallie

        You rock! :-)

      • http://develation.com scott

        micro’s my hero

    • http://test.com shaiju Thomas

      Yes , you absolutely rocks

  • http://chovy.com chovy

    Looks like you missed a step in the install:

    $ ./configure

    Do this first, then it works.

  • Ndubi

    Thanks for this! It’s a real lifesaver.

  • http://www.wesbos.com Wes Bos

    If anyone is trying to get this running on the latest version od Node.js you must do two things:

    1. Change response.sendHeader to response.writeHead
    2. change response.close() to response.end()

    • http://www.hashinsights.com Taariq

      THANK YOU!
      Took me 1-hour to figure that it was deprecated.
      cheers,
      t.

  • Vinny Benson

    change
    response.sendHeader(500, {“Content-Type”: “text/plain”});
    to
    response.setHeader(“content-type”, “text/plain”);

    and

    change
    response.close();
    to
    response.end();

    that worked for me….

    check out this documentation: http://nodejs.org/docs/v0.4.1/api/http.html
    thats how i figured it out

    happy noding

    • Kuldeep

      Hi Vinny,

      It looks like the code version difference .

  • http://aoberoi.me Ankur

    wow node must be moving super fast! this article is only a year old and the version number is significantly higher for the latest release, and the API in the examples is not just deprecated but unsupported in several places. not sure if this is a good or a bad thing, but just making note of how fast this project has changed.

  • mark

    OK. Really easy question…I’ve got node.js installed and running on my mac. I can do: node 1+3 and get 4, so I assume it’s running correctly. Now if I want to run a .js file, where do I put the file to run it from node.js?

  • http://gooddinosaur.com Jeff Iacono

    For anyone interested, I re-wrote the tweet streamer in Coffee Script and posted it to github: https://github.com/jeffreyiacono/node-tweetstreamer

    Includes updates to play nice with newer versions of Node (I’m using Node v0.4.4 and CoffeeScript v1.0.1).

  • http://www.heronote.com heronote
  • Danny

    It’s “setHeader”, not “sendHeader”.

  • Evert

    Unless I completely misunderstand this server-side JavaScript will fail like all those before it simply because it requires you to install it server-side and most people don’t have that kind of access on their web space.
    The same ailment as Ruby really. I know Ruby is a popular language, but what percentage of hosting companies actually give you ruby out-of-the-box?
    Besides, I fail to see the advantage of all this, we have HTML, CSS, PHP, SSI and JavaScript. All these new technologies like node.js are not really solving real, big problems, they are just variations on existing themes, in other words: commercialism.

    • http://www.age009gossipcenter.somee.com/ Osofem

      Thanks bro, u just completely put my thought into words. I dont see why i should learn it.

  • Bob

    The http hello world example is out of date, or wasn’t working on my system. Got it to work with:

    var sys = require(“sys”),
    http = require(“http”);

    http.createServer(function(request, response) {
    response.writeHead(“200″, {“Content-Type”: “text/html”});
    response.write(“Hello World!”);
    response.end();
    }).listen(8080);

    sys.puts(“Server running at http://localhost:8080/“);

    .

  • klimslava

    I have some problem with the JSON.parse this is the error i get

    undefined:1
    RT @joditdat: @
    ^^
    SyntaxError: Unexpected token ILLEGAL
    at Object.parse (native)
    at IncomingMessage. (/home/klimslava/Documents/DevProjects/TwitterFeed/staticServer.js:35:22)
    at IncomingMessage.emit (events.js:81:20)
    at HTTPParser.onMessageComplete (http.js:133:23)
    at Socket.ondata (http.js:1213:22)
    at Socket._onReadable (net.js:678:27)
    at IOWatcher.onReadable [as callback] (net.js:177:10)

  • Justin

    var sys = require(“sys”),
    http = require(“http”),
    url = require(“url”),
    path = require(“path”),
    fs = require(“fs”);

    http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
    if(!exists) {
    response.setHeader(“content-type”, “text/plain”);
    response.write(“404 Not Found\n”);
    response.end();
    return;
    }

    fs.readFile(filename, “binary”, function(err, file) {
    if(err) {
    response.setHeader(“content-type”, “text/plain”);
    response.write(err + “\n”);
    response.end();
    return;
    }

    response.setHeader(“content-type”, “text/plain”);
    response.write(file, “binary”);
    response.end();
    });
    });
    }).listen(8080);

    sys.puts(“Server running at http://localhost:8080/“);

    • http://nah.com Wyatt

      This code isnt updated, like:
      response.close(); should be response.end();
      and:
      response.sendHeader(); should be response.writeHead();

  • http://zacharymaril.com Zack Maril

    You need to update this. It no longer uses the correct api for nodejs.

  • http://juanmedin.com Juan Medín

    Good (very short) introduction. Useful as the very first contact with node.js

  • dpminusa

    The server.js example does not work in node 0.47. Try the following instead. Some methods have changed.

    var http = require(‘http’);

    http.createServer(function (request, response) {
    response.writeHead(200, {‘Content-Type’: ‘text/plain’});
    response.end(‘Hello World\n’);
    }).listen(8080);

    console.log(‘Server running at http://localhost:8080/‘);

    PS: This box does not work with IE9 unless you use compatibility mode.
    PPS: If you are a Gentoo user you will need to emerge V8 and nodejs both to get the system running.

    • http://level09.com Nidal

      I agree, This tutorial must be updated with the new API.

  • http://www.topecigsreviews.com Maq

    The link “Node.js documentation” (http://nodejs.org/api.html) is broken.

  • http://www.blurb.com/user/store/DanFarfan Dan Farfan

    Great job on original.
    Seems the platform has moved on a bit :-)

    Here’s a chunk that works for me on Node.js v0.5.3 on Windows ( along w/ some of the other helpful comments above ).

    http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    var handleTweets;

    if(uri === “/stream”) {
    handleTweets = function(tweets) {
    response.writeHead(200, { “Content-Type” : “text/plain” });
    response.write(JSON.stringify(tweets));
    response.end();

    clearTimeout(timeout);
    tweet_emitter.removeListener(“tweets”, handleTweets);
    }

    tweet_emitter.addListener(“tweets”, handleTweets);

    var timeout = setTimeout(function() {
    response.writeHead(200, { “Content-Type” : “text/plain” });
    response.write(JSON.stringify([]));
    response.end();

    tweet_emitter.removeListener(“tweets”, handleTweets);
    }, 10000);
    }
    else {
    load_static_file(uri, response);
    }
    }).listen(8080);

    Hope that helps!
    Dan

  • http://giulianoiacobelli.com Giuliano

    Nice tutorial but you should correct on step 3 the writing header function cause is no longer called that way:

    this is how it should appear running on NodeJS 0.4.1

    var sys = require(“sys”),
    http = require(“http”),
    url = require(“url”),
    path = require(“path”),
    fs = require(“fs”);

    http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
    if(!exists) {
    response.writeHead(404, {“Content-Type”: “text/plain”});
    response.write(“404 Not Found\n”);
    response.close();
    return;
    }

    fs.readFile(filename, “binary”, function(err, file) {
    if(err) {
    response.writeHead(500, {“Content-Type”: “text/plain”});
    response.write(err + “\n”);
    response.close();
    return;
    }

    response.writeHead(200);
    response.write(file, “binary”);
    response.close();
    });
    });
    }).listen(8080);

    sys.puts(“Server running at http://localhost:8080/“);

  • http://www.dynamical.nl Sietse

    This tutorial is old, it does not work anymore with the newest verions of NodeJS. Anyone who read this dont use this tutorial anymore. Look for documentation on the official NodeJS website.

  • http://--- yawo

    Super tutorial.

  • Debasis sabat

    Although the tutorial is old except for a beginner like me it simply offer me an temporary plan what Node.js is all regarding.
    Node.js is popping out to be a framework of alternative for building real-time applications of all types, from analytics systems to speak servers to location-based tracking services. If you’re already using Node, you almost certainly would like a database, and you only might need thought of using MongoDB.

  • Turtletrail

    download the latest version from github, but still have this kind of error:

    events.js:154
    throw new Error(‘removeListener only takes instances of Function’);

    even when i change the problematic line to this one:
    tweet_emitter.removeListener(“tweets”, listener);

    error remains.

    Any help appreciated

  • EllisGL

    The static file server you present has a big security hole in it.
    You can request something like ‘http://server:1111/../../../../../etc/passwd’

    • EllisGL

      Ignore that,

      FireFox was being stupid in my tests.

  • http://oscargodson.com Oscar Godson

    Alright, can we take this down now or update it? Its only confusing for beginners and is a total let down to get all started yet to only get a bunch of errors. I read this, tried it, and gave up and ended up having to read the docs myself.

  • http://www.id-meneo.com id meneo

    I had never heard of node.js before. I’ll dive in this tutorial, thx!

  • Ian

    This tut is using a lot of old code. Made a repo for this with updated code:
    https://github.com/ianleckey/twitter-node

  • Hiedi

    Fixed up code for the many errors including leaking the event listeners — here it is.

    var sys = require(“sys”),
    http = require(“http”),
    url = require(“url”),
    path = require(“path”),
    fs = require(“fs”),
    events = require(“events”);

    function load_static_file(uri, response) {
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
    if(!exists) {
    response.writeHead(404, {“Content-Type”: “text/plain”});
    response.write(“404 Not Found\n”);
    response.end();
    return;
    }

    fs.readFile(filename, “binary”, function(err, file) {
    if(err) {
    response.writeHead(500, {“Content-Type”: “text/plain”});
    response.write(err + “\n”);
    response.end();
    return;
    }

    response.writeHead(200);
    response.write(file, “binary”);
    response.end();
    });
    });
    }

    var twitter_client = http.createClient(80, “api.twitter.com”);
    var tweet_emitter = new events.EventEmitter();
    var i = 0;

    function get_tweets() {

    sys.puts(“calling twitter”);
    var request = twitter_client.request(“GET”, “/1/statuses/public_timeline.json”, {“host”: “api.twitter.com”});

    request.addListener(“response”, function(response) {
    var body = “”;
    response.addListener(“data”, function(data) {
    body += data;
    });

    response.addListener(“end”, function() {
    var tweets = JSON.parse(body);
    if(tweets.length > 0) {
    sys.puts(“here!”);
    tweet_emitter.emit(“tweets”, tweets);
    }
    });
    });

    request.end();
    }

    setInterval(get_tweets, 5000);

    http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    if(uri === “/stream”) {

    tweet_emitter.once(“tweets”, function(tweets) {
    response.writeHead(200, { “Content-Type” : “text/plain” });
    response.write(JSON.stringify(tweets));
    response.end();
    clearTimeout(timeout);
    });

    var timeout = setTimeout(function() {
    response.writeHead(200, { “Content-Type” : “text/plain” });
    response.write(JSON.stringify(["hi"]));
    response.end();

    }, 10000);

    }
    else {
    load_static_file(uri, response);
    }
    }).listen(8080);

    sys.puts(“Server running at http://localhost:8080/“);

  • http://brutalstudios.org JamesWorth

    The static file example throws a few erros, and i fixed ‘em, i uploaded the code here ;)

    http://codeviewer.org/view/code:2087