the node begineer book

102
The Node Beginner Book A Node.js tutorial by Manuel Kiessling About The aim of this document is to get you started with developing applications for Node.js, teaching you everything you need to know about "advanced" JavaScript along the way. It goes way beyond your typical "Hello World" tutorial. Status You are reading the final version of this book, i.e., updates are only done to correct errors or to reflect changes in new versions of Node.js. The code samples in this book are tested to work with Node.js version 0.4.9. Intended audience This document will probably fit best for readers that have a background similar to my own: experienced with at least one object-oriented language like Ruby, Python, PHP or Java, only little experience with JavaScript, and completely new Lee este tutorial en Español Читать этот учебник на русском Buy the ultimate Node.js bundle! Introduction plus reference in one bundle 226 pages in total - PDF, ePub & MOBI Direct download - free updates $10.98 $7.99 $7.99 Buy now! Buy now!

Upload: priyanka-tiwari

Post on 16-Apr-2015

1.093 views

Category:

Documents


4 download

DESCRIPTION

Very good book for initial web designing learning

TRANSCRIPT

Page 1: The Node Begineer Book

The Node Beginner BookA Node.js tutorial by Manuel Kiessling

AboutThe aim of this document is to get you started with developing applications forNode.js, teaching you everything you need to know about "advanced" JavaScriptalong the way. It goes way beyond your typical "Hello World" tutorial.

StatusYou are reading the final version of this book, i.e., updates are only done tocorrect errors or to reflect changes in new versions of Node.js.

The code samples in this book are tested to work with Node.js version 0.4.9.

Intended audienceThis document will probably fit best for readers that have a background similar tomy own: experienced with at least one object-oriented language like Ruby,Python, PHP or Java, only little experience with JavaScript, and completely new

Lee este tutorial en Español Читать этот учебник на русском

Buy the ultimate Node.js bundle!

Introduction plus reference in one bundle

226 pages in total - PDF, ePub & MOBI

Direct download - free updates

$10.98

$7.99$7.99

Buy now!Buy now!

Page 2: The Node Begineer Book

to Node.js.

Aiming at developers that already have experience with other programminglanguages means that this document won't cover really basic stuff like data types,variables, control structures and the likes. You already need to know about theseto understand this document.

However, because functions and objects in JavaScript are different from theircounterparts in most other languages, these will be explained in more detail.

Structure of this documentUpon finishing this document, you will have created a complete web applicationwhich allows the users of this application to view web pages and upload files.

Which, of course, is not exactly world-changing, but we will go some extra milesand not only create the code that is "just enough" to make these use casespossible, but create a simple, yet complete framework to cleanly separate thedifferent aspects of our application. You will see what I mean in a minute.

We will start with looking at how JavaScript development in Node.js is differentfrom JavaScript development in a browser.

Next, we will stay with the good old tradition of writing a "Hello World"application, which is a most basic Node.js application that "does" something.

Then, we will discuss what kind of "real" application we want to build, dissect thedifferent parts which need to be implemented to assemble this application, andstart working on each of these parts step-by-step.

As promised, along the way we will learn about some of the more advancedconcepts of JavaScript, how to make use of them, and look at why it makes senseto use these concepts instead of those we know from other programminglanguages.

The source code of the finished application is available through theNodeBeginnerBook Github repository.

Page 3: The Node Begineer Book

Table of contentsAbout

Status

Intended audience

Structure of this document

JavaScript and Node.js

JavaScript and You

A word of warning

Server-side JavaScript

"Hello World"

A full blown web application with Node.js

The use cases

The application stack

Building the application stack

A basic HTTP server

Analyzing our HTTP server

Passing functions around

How function passing makes our HTTP server work

Event-driven callbacks

How our server handles requests

Finding a place for our server module

What's needed to "route" requests?

Execution in the kingdom of verbs

Routing to real request handlers

Making the request handlers respond

How to not do it

Blocking and non-blocking

Responding request handlers with non-blocking operations

Serving something useful

Handling POST requests

Page 4: The Node Begineer Book

Handling file uploads

Conclusion and outlook

JavaScript and Node.js

JavaScript and YouBefore we talk about all the technical stuff, let's take a moment and talk aboutyou and your relationship with JavaScript. This chapter is here to allow you toestimate if reading this document any further makes sense for you.

If you are like me, you started with HTML "development" long ago, by writingHTML documents. You came along this funny thing called JavaScript, but youonly used it in a very basic way, adding interactivity to your web pages every nowand then.

What you really wanted was "the real thing", you wanted to know how to buildcomplex web sites - you learned a programming language like PHP, Ruby, Java,and started writing "backend" code.

Nevertheless, you kept an eye on JavaScript, you saw that with the introductionof jQuery, Prototype and the likes, things got more advanced in JavaScript land,and that this language really was about more than window.open().

However, this was all still frontend stuff, and although it was nice to have jQueryat your disposal whenever you felt like spicing up a web page, at the end of theday you were, at best, a JavaScript user, but not a JavaScript developer.

And then came Node.js. JavaScript on the server, how cool is that?

You decided that it's about time to check out the old, new JavaScript. But wait,writing Node.js applications is the one thing; understanding why they need to bewritten the way they are written means - understanding JavaScript. And this timefor real.

Here is the problem: Because JavaScript really lives two, maybe even three lives

Page 5: The Node Begineer Book

Here is the problem: Because JavaScript really lives two, maybe even three lives(the funny little DHMTL helper from the mid-90's, the more serious frontendstuff like jQuery and the likes, and now server-side), it's not that easy to findinformation that helps you to learn JavaScript the "right" way, in order to writeNode.js applications in a fashion that makes you feel you are not just usingJavaScript, you are actually developing it.

Because that's the catch: you already are an experienced developer, you don'twant to learn a new technique by just hacking around and mis-using it; you wantto be sure that you are approaching it from the right angle.

There is, of course, excellent documentation out there. But documentation alonesometimes isn't enough. What is needed is guidance.

My goal is to provide a guide for you.

A word of warningThere are some really excellent JavaScript people out there. I'm not one of them.

I'm really just the guy I talked about in the previous paragraph. I know a thing ortwo about developing backend web applications, but I'm still new to "real"JavaScript and still new to Node.js. I learned some of the more advanced aspectsof JavaScript just recently. I'm not experienced.

Which is why this is no "from novice to expert" book. It's more like "from noviceto advanced novice".

If I don't fail, then this will be the kind of document I wish I had when startingwith Node.js.

Server-side JavaScriptThe first incarnations of JavaScript lived in browsers. But this is just the context.It defines what you can do with the language, but it doesn't say much about whatthe language itself can do. JavaScript is a "complete" language: you can use it inmany contexts and achieve everything with it you can achieve with any other"complete" language.

Page 6: The Node Begineer Book

Node.js really is just another context: it allows you to run JavaScript code in thebackend, outside a browser.

In order to execute the JavaScript you intend to run in the backend, it needs to beinterpreted and, well, executed. This is what Node.js does, by making use ofGoogle's V8 VM, the same runtime environment for JavaScript that GoogleChrome uses.

Plus, Node.js ships with a lot of useful modules, so you don't have to writeeverything from scratch, like for example something that outputs a string on theconsole.

Thus, Node.js is really two things: a runtime environment and a library.

In order to make use of these, you need to install Node.js. Instead of repeatingthe process here, I kindly ask you to visit the official installation instructions.Please come back once you are up and running.

"Hello World"Ok, let's just jump in the cold water and write our first Node.js application: "HelloWorld".

Open your favorite editor and create a file called helloworld.js. We want it towrite "Hello World" to STDOUT, and here is the code needed to do that:

console.log("Hello World");

Save the file, and execute it through Node.js:

node helloworld.js

This should output Hello World on your terminal.

Ok, this stuff is boring, right? Let's write some real stuff.

Page 7: The Node Begineer Book

Ok, this stuff is boring, right? Let's write some real stuff.

A full blown web application with Node.js

The use casesLet's keep it simple, but realistic:

The user should be able to use our application with a web browser

The user should see a welcome page when requesting http://domain/startwhich displays a file upload form

By choosing an image file to upload and submitting the form, this imageshould then be uploaded to http://domain/upload, where it is displayedonce the upload is finished

Fair enough. Now, you could achieve this goal by googling and hacking togethersomething. But that's not what we want to do here.

Furthermore, we don't want to write only the most basic code to achieve the goal,however elegant and correct this code might be. We will intentionally add moreabstraction than necessary in order to get a feeling for building more complexNode.js applications.

The application stackLet's dissect our application. Which parts need to be implemented in order tofulfill the use cases?

We want to serve web pages, therefore we need an HTTP server

Our server will need to answer differently to requests, depending on whichURL the request was asking for, thus we need some kind of router in orderto map requests to request handlers

To fullfill the requests that arrived at the server and have been routed usingthe router, we need actual request handlers

The router probably should also treat any incoming POST data and give it tothe request handlers in a convenient form, thus we need request datahandling

Page 8: The Node Begineer Book

We not only want to handle requests for URLs, we also want to displaycontent when these URLs are requested, which means we need some kindof view logic the request handlers can use in order to send content to theuser's browser

Last but not least, the user will be able to upload images, so we are going toneed some kind of upload handling which takes care of the details

Let's think a moment about how we would build this stack with PHP. It's notexactly a secret that the typical setup would be an Apache HTTP server withmod_php5 installed. Which in turn means that the whole "we need to be able to serve web pages andreceive HTTP requests" stuff doesn't happen within PHP itself.

Well, with node, things are a bit different. Because with Node.js, we not onlyimplement our application, we also implement the whole HTTP server. In fact,our web application and its web server are basically the same.

This might sound like a lot of work, but we will see in a moment that withNode.js, it's not.

Let's just start at the beginning and implement the first part of our stack, theHTTP server.

Building the application stack

A basic HTTP serverWhen I arrived at the point where I wanted to start with my first "real" Node.jsapplication, I wondered not only how to actually code it, but also how to organizemy code. Do I need to have everything in one file? Most tutorials on the web that teach youhow to write a basic HTTP server in Node.js have all the logic in one place. Whatif I want to make sure that my code stays readable the more stuff I implement?

Turns out, it's relatively easy to keep the different concerns of your codeseparated, by putting them in modules.

Page 9: The Node Begineer Book

This allows you to have a clean main file, which you execute with Node.js, andclean modules that can be used by the main file and among each other.

So, let's create a main file which we use to start our application, and a module filewhere our HTTP server code lives.

My impression is that it's more or less a standard to name your main file index.js.It makes sense to put our server module into a file named server.js.

Let's start with the server module. Create the file server.js in the root directory ofyour project, and fill it with the following code:

var http = require("http");

http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end();}).listen(8888);

That's it! You just wrote a working HTTP server. Let's prove it by running andtesting it. First, execute your script with Node.js:

node server.js

Now, open your browser and point it at http://localhost:8888/. This shoulddisplay a web page that says "Hello World".

That's quite interesting, isn't it. How about talking about what's going on hereand leaving the question of how to organize our project for later? I promise we'llget back to it.

Analyzing our HTTP serverWell, then, let's analyze what's actually going on here.

The first line requires the http module that ships with Node.js and makes it

Page 10: The Node Begineer Book

accessible through the variable http.

We then call one of the functions the http module offers: createServer. Thisfunction returns an object, and this object has a method named listen, and takesa numeric value which indicates the port number our HTTP server is going tolisten on.

Please ignore for a second the function definition that follows the openingbracket of http.createServer.

We could have written the code that starts our server and makes it listen at port8888 like this:

var http = require("http");

var server = http.createServer();server.listen(8888);

That would start an HTTP server listening at port 8888 and doing nothing else(not even answering any incoming requests).

The really interesting (and, if your background is a more conservative languagelike PHP, odd looking) part is the function definition right there where you wouldexpect the first parameter of the createServer() call.

Turns out, this function definition IS the first (and only) parameter we are givingto the createServer() call. Because in JavaScript, functions can be passed aroundlike any other value.

Passing functions aroundYou can, for example, do something like this:

function say(word) { console.log(word);}

function execute(someFunction, value) { someFunction(value);}

Page 11: The Node Begineer Book

execute(say, "Hello");

Read this carefully! What we are doing here is, we pass the function say as thefirst parameter to the execute function. Not the return value of say, but say itself!

Thus, say becomes the local variable someFunction within execute, and executecan call the function in this variable by issuing someFunction() (addingbrackets).

Of course, because say takes one parameter, execute can pass such a parameterwhen calling someFunction.

We can, as we just did, pass a function as a parameter to another function by itsname. But we don't have to take this indirection of first defining, then passing it -we can define and pass a function as a parameter to another function in-place:

function execute(someFunction, value) { someFunction(value);}

execute(function(word){ console.log(word) }, "Hello");

We define the function we want to pass to execute right there at the place whereexecute expects its first parameter.

This way, we don't even need to give the function a name, which is why this iscalled an anonymous function.

This is a first glimpse at what I like to call "advanced" JavaScript, but let's take itstep by step. For now, let's just accept that in JavaScript, we can pass a functionas a parameter when calling another function. We can do this by assigning ourfunction to a variable, which we then pass, or by defining the function to pass in-place.

How function passing makes our HTTP serverwork

Page 12: The Node Begineer Book

With this knowledge, let's get back to our minimalistic HTTP server:

var http = require("http");

http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end();}).listen(8888);

By now it should be clear what we are actually doing here: we pass thecreateServer function an anonymous function.

We could achieve the same by refactoring our code to:

var http = require("http");

function onRequest(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end();}

http.createServer(onRequest).listen(8888);

Maybe now is a good moment to ask: Why are we doing it that way?

Event-driven callbacksThe answer is a) not that easy to give (at least for me), and b) lies in the verynature of how Node.js works. It's event-driven, which is the reason why it's sofast.

You might want to take the time to read Felix Geisendörfer's excellent postUnderstanding node.js for some background explanation.

It all boils down to the fact that Node.js works event-driven. Oh and yes, I, too,don't know exactly what that means. But I will try and explain, why this makessense for us who want to write web based applications in Node.js.

When we call the http.createServer method, we of course not only want to have a

Page 13: The Node Begineer Book

When we call the http.createServer method, we of course not only want to have aserver listening at some port, we also want to do something when there is anHTTP request to this server.

The problem is, this happens asynchronously: it happens at any given time, butwe only have a single process in which our server runs.

When writing PHP applications, we aren't bothered by this at all: whenever thereis an incoming HTTP request, the webserver (usually Apache) forks a newprocess for just this request, and starts the according PHP script from scratch,which is then executed from top to bottom.

So in regards of control flow, we are in the midst of our Node.js program when anew request arrives at port 8888 - how to handle this without going insane?

Well, this is where the event-driven design of Node.js/JavaScript actually helps,although we need to learn some new concepts in order to master it. Let's see howthese concepts are applied in our server code.

We create the server, and pass a function to the method creating it. Wheneverour server receives a request, the function we passed will be called.

We don't know when this is going to happen, but we now have a place where wecan handle an incoming request. It's our passed function, no matter if we firstdefined it or passed it anonymously.

This concept is called a callback. We pass into some method a function, and themethod uses this function to call back if an event related to the method occurs.

At least for me, this took some time to understand. Just read Felix' blog postagain if you are still unsure.

Let's play around a bit with this new concept. Can we prove that our codecontinues after creating the server, even if no HTTP request happened and thecallback function we passed isn't called? Let's try it:

var http = require("http");

function onRequest(request, response) { console.log("Request received.");

Page 14: The Node Begineer Book

response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end();}

http.createServer(onRequest).listen(8888);

console.log("Server has started.");

Note that I use console.log to output a text whenever the onRequest function (ourcallback) is triggered, and another text right after starting the HTTP server.

When we start this (node server.js, as always), it will immediately output "Serverhas started." on the command line. Whenever we request our server (by openinghttp://localhost:8888/ in our browser), the message "Request received." isprinted on the command line.

Event-driven asynchronous server-side JavaScript with callbacks in action :-)

(Note that our server will probably write "Request received." to STDOUT twotimes upon opening the page in a browser. That's because most browser will tryto load the favicon by requesting http://localhost:8888/favicon.ico wheneveryou open http://localhost:8888/).

How our server handles requestsOk, let's quickly analyze the rest of our server code, that is, the body of ourcallback function onRequest().

When the callback fires and our onRequest() function gets triggered, twoparameters are passed into it: request and response.

Those are objects, and you can use their methods to handle the details of theHTTP request that occured and to respond to the request (i.e., to actually sendsomething over the wire back to the browser that requested your server).

And our code does just that: Whenever a request is received, it uses theresponse.writeHead() function to send an HTTP status 200 and content-type inthe HTTP response header, and the response.write() function to send the text"Hello World" in the HTTP response body.

Page 15: The Node Begineer Book

At last, we call response.end() to actually finish our response.

At this point, we don't care for the details of the request, which is why we don'tuse the request object at all.

Finding a place for our server moduleOk, I promised we will get back to how to organize our application. We have thecode for a very basic HTTP server in the file server.js, and I mentioned that it'scommon to have a main file called index.js which is used to bootstrap and startour application by making use of the other modules of the application (like theHTTP server module that lives in server.js).

Let's talk about how to make server.js a real Node.js module that can be used byour yet-to-be-written index.js main file.

As you may have noticed, we already used modules in our code, like this:

var http = require("http");

...

http.createServer(...);

Somewhere within Node.js lives a module called "http", and we can make use of itin our own code by requiring it and assigning the result of the require to a localvariable.

This makes our local variable an object that carries all the public methods the httpmodule provides.

It's common practice to choose the name of the module for the name of the localvariable, but we are free to choose whatever we like:

var foo = require("http");

...

foo.createServer(...);

Page 16: The Node Begineer Book

Fine, it's clear how to make use of internal Node.js modules. How do we createour own modules, and how do we use them?

Let's find out by turning our server.js script into a real module.

Turns out, we don't have to change that much. Making some code a modulemeans we need to export those parts of its functionality that we want to provideto scripts that require our module.

For now, the functionality our HTTP server needs to export is simple: scriptsrequiring our server module simply need to start the server.

To make this possible, we will put our server code into a function named start,and we will export this function:

var http = require("http");

function start() { function onRequest(request, response) { console.log("Request received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

This way, we can now create our main file index.js, and start our HTTP there,although the code for the server is still in our server.js file.

Create a file index.js with the following content:

var server = require("./server");

server.start();

As you can see, we can use our server module just like any internal module: byrequiring its file and assigning it to a variable, its exported functions become

Page 17: The Node Begineer Book

available to us.

That's it. We can now start our app via our main script, and it still does exactly thesame:

node index.js

Great, we now can put the different parts of our application into different filesand wire them together by making them modules.

We still have only the very first part of our application in place: we can receiveHTTP requests. But we need to do something with them - depending on whichURL the browser requested from our server, we need to react differently.

For a very simple application, you could do this directly within the callbackfunction onRequest(). But as I said, let's add a bit more abstraction in order tomake our example application a bit more interesting.

Making different HTTP requests point at different parts of our code is called"routing" - well, then, let's create a module called router.

What's needed to "route" requests?We need to be able to feed the requested URL and possible additional GET andPOST parameters into our router, and based on these the router then needs to beable to decide which code to execute (this "code to execute" is the third part of ourapplication: a collection of request handlers that do the actual work when arequest is received).

So, we need to look into the HTTP requests and extract the requested URL aswell as the GET/POST parameters from them. It could be argued if that should bepart of the router or part of the server (or even a module of its own), but let's justagree on making it part of our HTTP server for now.

All the information we need is available through the request object which ispassed as the first parameter to our callback function onRequest(). But to

Page 18: The Node Begineer Book

interpret this information, we need some additional Node.js modules, namely urland querystring.

The url module provides methods which allow us to extract the different parts ofa URL (like e.g. the requested path and query string), and querystring can in turnbe used to parse the query string for request parameters:

url.parse(string).query | url.parse(string).pathname | | | | | ------ -------------------http://localhost:8888/start?foo=bar&hello=world --- ----- | | | | querystring(string)["foo"] | | querystring(string)["hello"]

We can, of course, also use querystring to parse the body of a POST request forparameters, as we will see later.

Let's now add to our onRequest() function the logic needed to find out whichURL path the browser requested:

var http = require("http");var url = require("url");

function start() { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

Fine. Our application can now distinguish requests based on the URL pathrequested - this allows us to map requests to our request handlers based on the

Page 19: The Node Begineer Book

URL path using our (yet to be written) router.

In the context of our application, it simply means that we will be able to haverequests for the /start and /upload URLs handled by different parts of our code.We will see how everything fits together soon.

Ok, it's time to actually write our router. Create a new file called router.js, withthe following content:

function route(pathname) { console.log("About to route a request for " + pathname);}

exports.route = route;

Of course, this code basically does nothing, but that's ok for now. Let's first seehow to wire together this router with our server before putting more logic into therouter.

Our HTTP server needs to know about and make use of our router. We couldhard-wire this dependency into the server, but because we learned the hard wayfrom our experience with other programming languages, we are going to looselycouple server and router by injecting this dependency (you may want to readMartin Fowlers excellent post on Dependency Injection for backgroundinformation).

Let's first extend our server's start() function in order to enable us to pass theroute function to be used by parameter:

var http = require("http");var url = require("url");

function start(route) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");

route(pathname);

response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }

Page 20: The Node Begineer Book

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

And let's extend our index.js accordingly, that is, injecting the route function ofour router into the server:

var server = require("./server");var router = require("./router");

server.start(router.route);

Again, we are passing a function, which by now isn't any news for us.

If we start our application now (node index.js, as always), and request an URL,you can now see from the application's output that our HTTP server makes use ofour router and passes it the requested pathname:

bash$ node index.jsRequest for /foo received.About to route a request for /foo

(I omitted the rather annoying output for the /favicon.ico request).

Execution in the kingdom of verbsMay I once again stray away for a while and talk about functional programmingagain?

Passing functions is not only a technical consideration. With regard to softwaredesign, it's almost philosophical. Just think about it: in our index file, we couldhave passed the router object into the server, and the server could have called thisobject's route function.

This way, we would have passed a thing, and the server would have used thisthing to do something. Hey, router thing, could you please route this for me?

Page 21: The Node Begineer Book

But the server doesn't need the thing. It only needs to get something done, and toget something done, you don't need things at all, you need actions. You don'tneed nouns, you need verbs.

Understanding the fundamental mind-shift that's at the core of this idea is whatmade me really understand functional programming.

And I did understand it when reading Steve Yegge's masterpiece Execution in theKingdom of Nouns. Go read it now, really. It's one of the best writings related tosoftware I ever had the pleasure to encounter.

Routing to real request handlersBack to business. Our HTTP server and our request router are now best friendsand talk to each other as we intended.

Of course, that's not enough. "Routing" means, we want to handle requests todifferent URLs differently. We would like to have the "business logic" forrequests to /start handled in another function than requests to /upload.

Right now, the routing "ends" in the router, and the router is not the place toactually "do" something with the requests, because that wouldn't scale well onceour application becomes more complex.

Let's call these functions, where requests are routed to, request handlers. Andlet's tackle those next, because unless we have these in place there isn't muchsense in doing anything with the router for now.

New application part, new module - no surprise here. Let's create a module calledrequestHandlers, add a placeholder function for every request handler, andexport these as methods of the module:

function start() { console.log("Request handler 'start' was called.");}

function upload() { console.log("Request handler 'upload' was called.");}

exports.start = start;

Page 22: The Node Begineer Book

exports.upload = upload;

This allows us to wire the request handlers into the router, giving our routersomething to route to.

At this point we need to make a decision: do we hard-code usage of therequestHandlers module into the router, or do we want a bit more dependencyinjection? Although dependency injection, like every other pattern, shouldn't beused only for the sake of using it, in this case it makes sense to loosely couple therouter and its request handlers, and thus making the router really reusable.

This means we need to pass the request handlers from our server into our router,but this feels even more wrong, which is why we should go the whole way andpass them to the server from our main file, and passing it on to the router fromthere.

How are we going to pass them? Right now we have two handlers, but in a realapplication, this number is going to increase and vary, and we sure don't want tofiddle around mapping requests to handlers in the router anytime a new URL /request handler is added. And having some if request == x then call handler y inthe router would be more than ugly.

A varying number of items, each mapped to a string (the requested URL)? Well,sounds like an associative array would be a perfect fit.

Well, this finding is slightly disappointed by the fact that JavaScript doesn'tprovide associative array - or does it? Turns out, it's actually objects that we wantto use if we need an associative array!

There's a nice introduction to this at http://msdn.microsoft.com/en-us/magazine/cc163419.aspx, let me quote the relevant part:

In C++ or C#, when we’re talking about objects, we're referring toinstances of classes or structs. Objects have different properties andmethods, depending on which templates (that is, classes) they areinstantiated from. That's not the case with JavaScript objects. InJavaScript, objects are just collections of name/value pairs - think of a

Page 23: The Node Begineer Book

JavaScript object as a dictionary with string keys.

If JavaScript objects are just collections of name/value pairs, how can they havemethods? Well, the values can be strings, numbers etc. - or functions!

Ok, now finally back to the code. We decided we want to pass the list ofrequestHandlers as an object, and in order to achieve loose coupling we want toinject this object into the route().

Let's start with putting the object together in our main file index.js:

var server = require("./server");var router = require("./router");var requestHandlers = require("./requestHandlers");

var handle = {}handle["/"] = requestHandlers.start;handle["/start"] = requestHandlers.start;handle["/upload"] = requestHandlers.upload;

server.start(router.route, handle);

Although handle is more of a "thing" (a collection of request handlers), I proposewe name it like a verb, because this will result in a fluent expression in our router,as we will see soon.

As you can see, it's really simple to map different URLs to the same requesthandler: by adding a key/value pair of "/" and requestHandlers.start, we canexpress in a nice and clean way that not only requests to /start, but also requeststo / shall be handled by the start handler.

After defining our object, we pass it into the server as an additional parameter.Let's change our server.js to make use of it:

var http = require("http");var url = require("url");

function start(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");

route(handle, pathname);

Page 24: The Node Begineer Book

response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

We've added the handle parameter to our start() function, and pass the handleobject on to the route() callback, as its first parameter.

Let's change the route() function accordingly, in our router.js file:

function route(handle, pathname) { console.log("About to route a request for " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](); } else { console.log("No request handler found for " + pathname); }}

exports.route = route;

What we do here is, we check if a request handler for the given pathname exists,and if it does, we simply call the according function. Because we can access ourrequest handler functions from our object just as we would access an element ofan associative array, we have this nice fluent handle[pathname](); expression Italked about earlier: "Please, handle this pathname".

Ok, that's all we need to wire server, router, and request handlers together! Whenstarting our application and requesting http://localhost:8888/start in ourbrowser, we can prove that the correct request handler was indeed called:

Server has started.Request for /start received.About to route a request for /startRequest handler 'start' was called.

And opening http://localhost:8888/ in our browser proves that these requests,

Page 25: The Node Begineer Book

And opening http://localhost:8888/ in our browser proves that these requests,too, are indeed handled by the start request handler:

Request for / received.About to route a request for /Request handler 'start' was called.

Making the request handlers respondBeautiful. Now if only the request handlers could actually send something back tothe browser, that would be even better, right?

Remember, the "Hello World" your browser displays upon requesting a page stillcomes from the onRequest function in our server.js file.

"Handling request" means "answering requests" after all, thus we need to enableour request handlers to speak with the browser just like our onRequest functiondoes.

How to not do it

The straight-forward approach we - as developers with a background in PHP orRuby - might want to follow is actually very deceitful: it works like a charm,seems to make a lot of sense, and then suddenly screws things up when we don'texpect it.

What I mean by "straight-forward approach" is this: make the request handlersreturn() the content they want to display to the user, and send this response datain the onRequest function back to the user.

Let's just do this, and then see why it's not such an overly good idea.

We start with the request handlers and make them return what we would like todisplay in the browser. We need to change requestHandlers.js to this:

function start() { console.log("Request handler 'start' was called.");

Page 26: The Node Begineer Book

return "Hello Start";}

function upload() { console.log("Request handler 'upload' was called."); return "Hello Upload";}

exports.start = start;exports.upload = upload;

Good. Likewise, the router needs to return to the server what the requesthandlers return to him. We therefore need to edit router.js like this:

function route(handle, pathname) { console.log("About to route a request for " + pathname); if (typeof handle[pathname] === 'function') { return handle[pathname](); } else { console.log("No request handler found for " + pathname); return "404 Not found"; }}

exports.route = route;

As you can see, we also return some text if the request could not be routed.

And last but not least, we need to refactor our server to make it respond to thebrowser with the content the request handlers returned via the router,transforming server.js into:

var http = require("http");var url = require("url");

function start(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");

response.writeHead(200, {"Content-Type": "text/plain"}); var content = route(handle, pathname) response.write(content); response.end(); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

Page 27: The Node Begineer Book

If we start our rewritten application, everything works like a charm: requestinghttp://localhost:8888/start results in "Hello Start" being displayed in thebrowser, requesting http://localhost:8888/upload gives us "Hello Upload", andhttp://localhost:8888/foo produces "404 Not found".

Ok, then why is that a problem? The short answer: because we will run intoproblems if one of the request handlers wants to make use of a non-blockingoperation in the future.

Let's take a bit more time for the long answer.

Blocking and non-blocking

As said, the problems will arise when we include non-blocking operations in therequest handlers. But let's talk about blocking operations first, then about non-blocking operations.

And instead of trying to explain what "blocking" and "non-blocking" means, let'sdemonstrate ourselves what happens if we add a blocking operation to ourrequest handlers.

To do this, we will modify our start request handler to make it wait 10 secondsbefore returning its "Hello Start" string. Because there is no such thing as sleep()in JavaScript, we will use a clever hack for that.

Please modify requestHandlers.js as follows:

function start() { console.log("Request handler 'start' was called.");

function sleep(milliSeconds) { var startTime = new Date().getTime(); while (new Date().getTime() < startTime + milliSeconds); }

sleep(10000); return "Hello Start";}

function upload() { console.log("Request handler 'upload' was called.");

Page 28: The Node Begineer Book

return "Hello Upload";}

exports.start = start;exports.upload = upload;

Just to make clear what that does: when the function start() is called, Node.jswaits 10 seconds and only then returns "Hello Start". When calling upload(), itreturns immediately, just like before.

(Of course, you should imagine that instead of sleeping for 10 seconds, therewould be a real life blocking operation in start(), like some sort of long-runningcomputation.)

Let's see what this change does.

As always, we need to restart our server. This time, I ask you to follow a slightlycomplex "protocol" in order to see what happens: First, open two browserwindows or tabs. In the first browser window, please enterhttp://localhost:8888/start into the address bar, but do not yet open this url!

In the second browser window's address bar, enterhttp://localhost:8888/upload, and again, please do not yet hit enter.

Now, do as follows: hit enter on the first window ("/start"), then quickly changeto the second window ("/upload") and hit enter, too.

What you will notice is this: The /start URL takes 10 seconds to load, as we wouldexpect. But the /upload URL also takes 10 seconds to load, although there is nosleep() in the according request handler!

Why? Because start() contains a blocking operation. Like in "it's blockingeverything else from working".

And that is a problem, because, as the saying goes: "In node, everything runs inparallel, except your code".

What that means is that Node.js can handle a lot of concurrent stuff, but doesn'tdo this by splitting everything into threads - in fact, Node.js is single-threaded.

Page 29: The Node Begineer Book

Instead, it does so by running an event loop, and we the developers can make useof this - we should avoid blocking operations whenever possible, and use non-blocking operations instead.

But to do so, we need to make use of callbacks by passing functions around toother functions that might do something that takes some time (like, e.g. sleep for10 seconds, or query a database, or do some expensive calculation).

This way we are saying "Hey, probablyExpensiveFunction(), please do yourstuff, but I, the single Node.js thread, am not going to wait right here until youare finished, I will continue to execute the lines of code below you, so would youplease take this callbackFunction() here and call it when you are finished doingyour expensive stuff? Thanks!"

(If you would like to read about that in more detail, please have a look at Mixu'spost on Understanding the node.js event loop.)

And we will now see why the way we constructed the "request handler responsehandling" in our application doesn't allow us to make proper use of non-blockingoperations.

Once again, let's try to experience the problem first-hand by modifying ourapplication.

We are going to use our start request handler for this again. Please modify it toreflect the following (file requestHandlers.js):

var exec = require("child_process").exec;

function start() { console.log("Request handler 'start' was called."); var content = "empty";

exec("ls -lah", function (error, stdout, stderr) { content = stdout; });

return content;}

function upload() { console.log("Request handler 'upload' was called."); return "Hello Upload";}

Page 30: The Node Begineer Book

exports.start = start;exports.upload = upload;

As you can see, we just introduced a new Node.js module, child_process. We didso because it allows us to make use of a very simple yet useful non-blockingoperation: exec().

What exec() does is, it executes a shell command from within Node.js. In thisexample, we are going to use it to get a list of all files in the current directory ("ls -lah"), allowing us to display this list in the browser of a user requesting the /startURL.

What the code does is straightforward: create a new variable content (with aninitial value of "empty"), execute "ls -lah", fill the variable with the result, andreturn it.

As always, we will start our application, and visit http://localhost:8888/start.

Which loads a beautiful web page that displays the string "empty". What's goingwrong here?

Well, as you may have already guessed, exec() does its magic in a non-blockingfashion. That's a good thing, because this way we can execute very expensiveshell operations (like, e.g., copying huge files around or similar stuff) withoutforcing our application into a full stop as the blocking sleep operation did.

(If you would like to prove this, replace "ls -lah" with a more expensive operationlike "find /").

But we aren't exactly happy with our elegant non-blocking operation, when ourbrowser doesn't display its result, right?

Well, then, let's fix it. And while we are at it, let's try to understand why thecurrent architecture doesn't work.

The problem is that exec(), in order to work non-blocking, makes use of acallback function.

Page 31: The Node Begineer Book

In our example, it's an anonymous function which is passed as the secondparameter to the exec() function call:

function (error, stdout, stderr) { content = stdout;}

And herein lies the root of our problem: our own code is executed synchronous,which means that immediately after calling exec(), Node.js continues to executereturn content;. At this point, content is still "empty", due to the fact that thecallback function passed to exec() has not yet been called - because exec()operates asynchronous.

Now, "ls -lah" is a very inexpensive and fast operation (unless there are millionsof files in the directory). Which is why the callback is called relatively expeditious- but it nevertheless happens asynchronously.

Thinking about a more expensive command makes this more obvious: "find /"takes about 1 minute on my machine, but if I replace "ls -lah" with "find /" in therequest handler, I still immediately receive an HTTP response when opening the/start URL - it's clear that exec() does something in the background, whileNode.js itself continues with the application, and we may assume that thecallback function we passed into exec() will be called only when the "find /"command has finished running.

But how can we achieve our goal, i.e. showing the user a list of files in the currentdirectory?

Well, after learning how to not do it, let's discuss how to make our requesthandlers respond to browser requests the right way.

Responding request handlers with non-blockingoperations

I've just used the phrase "the right way". Dangerous stuff. Quite often, there is nosingle "right way".

But one possible solution for this is, as often with Node.js, to pass functions

Page 32: The Node Begineer Book

But one possible solution for this is, as often with Node.js, to pass functionsaround. Let's examine this.

Right now, our application is able to transport the content (which the requesthandlers would like to display to the user) from the request handlers to the HTTPserver by returning it up through the layers of the application (request handler ->router -> server).

Our new approach is as follows: instead of bringing the content to the server, wewill bring the server to the content. To be more precise, we will inject theresponse object (from our server's callback function onRequest()) through therouter into the request handlers. The handlers will then be able to use thisobject's functions to respond to requests themselves.

Enough explanation, here is the step by step recipe on how to change ourapplication.

Let's start with our server.js:

var http = require("http");var url = require("url");

function start(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");

route(handle, pathname, response); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

Instead of expecting a return value from the route() function, we pass it a thirdparameter, our response object. Furthermore, we removed any response methodcalls from the onRequest() handler, because we now expect route to take care ofthat.

Next comes router.js:

function route(handle, pathname, response) {

Page 33: The Node Begineer Book

function route(handle, pathname, response) { console.log("About to route a request for " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response); } else { console.log("No request handler found for " + pathname); response.writeHead(404, {"Content-Type": "text/plain"}); response.write("404 Not found"); response.end(); }}

exports.route = route;

Same pattern: instead of expecting a return value from our request handlers, wepass the respond object on.

If no request handler can be used, we now take care of responding with a proper"404" header and body ourselves.

And last but not least, we modify requestHandlers.js:

var exec = require("child_process").exec;

function start(response) { console.log("Request handler 'start' was called.");

exec("ls -lah", function (error, stdout, stderr) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write(stdout); response.end(); });}

function upload(response) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello Upload"); response.end();}

exports.start = start;exports.upload = upload;

Our handler functions need to accept the response parameter, and have to makeuse of them in order to respond to the request directly.

The start handler will respond from within the anonymous exec() callback, andthe upload handler still simply replies with "Hello Upload", but now by making

Page 34: The Node Begineer Book

use of the response object.

If we start our application again (node index.js), this should work as expected.

If you would like to prove that an expensive operation behind /start will nolonger block requests for /upload from answering immediately, then modify yourrequestHandlers.js as follows:

var exec = require("child_process").exec;

function start(response) { console.log("Request handler 'start' was called.");

exec("find /", { timeout: 10000, maxBuffer: 20000*1024 }, function (error, stdout, stderr) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write(stdout); response.end(); });}

function upload(response) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello Upload"); response.end();}

exports.start = start;exports.upload = upload;

This will make HTTP requests to http://localhost:8888/start take at least 10seconds, but requests to http://localhost:8888/upload will be answeredimmediately, even if /start is still computing.

Serving something usefulUntil now, what we have done is all fine and dandy, but we haven't created anyvalue for the customers of our award-winning website.

Our server, router, and request handlers are in place, thus now we can begin toadd content to our site which allows our users to interact and walk through theuse case of choosing a file, uploading this file, and viewing the uploaded file in thebrowser. For the sake of simplicity we will assume that only image files are going

Page 35: The Node Begineer Book

to be uploaded and displayed through the application.

Ok, let's take it step by step, but with most of the techniques and principles ofJavaScript explained by now, let's at the same time accelerate a bit. This authorlikes to hear himself talking way too much anyways.

Here, step by step means roughly two steps: We will first look at how to handleincoming POST requests (but not file uploads), and in a second step, we willmake use of an external Node.js module for the file upload handling. I've chosenthis approach for two reasons.

First, handling basic POST requests is relatively simple with Node.js, but stillteaches us enough to be worth exercising it. Second, handling file uploads (i.e., multipart POST requests) is not simple withNode.js, and therefore is beyond the scope of this tutorial, but using an externalmodule is itself a lesson that makes sense to be included in a beginner's tutorial.

Handling POST requests

Let's keep this banally simple: We will present a textarea that can be filled by theuser and submitted to the server in a POST request. Upon receiving and handlingthis request, we will display the content of the textarea.

The HTML for this textarea form needs to be served by our /start request handler, solet's add it right away, in file requestHandlers.js:

function start(response) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" content="text/html; '+ 'charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" method="post">'+ '<textarea name="text" rows="20" cols="60"></textarea>'+ '<input type="submit" value="Submit text" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();

Page 36: The Node Begineer Book

}

function upload(response) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello Upload"); response.end();}

exports.start = start;exports.upload = upload;

Now if this isn't going to win the Webby Awards, then I don't know what could.You should see this very simple form when requestinghttp://localhost:8888/start in your browser. If not, you probably didn't restartthe application.

I hear you: having view content right in the request handler is ugly. However, Idecided to not include that extra level of abstraction (i.e., separating view andcontroller logic) in this tutorial, because I think that it doesn't teach us anythingworth knowing in the context of JavaScript or Node.js.

Let's rather use the remaining screen space for a more interesting problem, thatis, handling the POST request that will hit our /upload request handler when theuser submits this form.

Now that we are becoming expert novices, we are no longer surprised by the factthat handling POST data is done in a non-blocking fashion, by usingasynchronous callbacks.

Which makes sense, because POST requests can potentially be very large -nothing stops the user from entering text that is multiple megabytes in size.Handling the whole bulk of data in one go would result in a blocking operation.

To make the whole process non-blocking, Node.js serves our code the POST datain small chunks, callbacks that are called upon certain events. These events aredata (an new chunk of POST data arrives) and end (all chunks have beenreceived).

We need to tell Node.js which functions to call back to when these events occur.This is done by adding listeners to the request object that is passed to our

Page 37: The Node Begineer Book

onRequest callback whenever an HTTP request is received.

This basically looks like this:

request.addListener("data", function(chunk) { // called when a new chunk of data was received});

request.addListener("end", function() { // called when all chunks of data have been received});

The question arises where to implement this logic. We currently can access therequest object in our server only - we don't pass it on to the router and therequest handlers, like we did with the response object.

In my opinion, it's an HTTP servers job to give the application all the data from arequests it needs to do its job. Therefore, I suggest we handle the POST dataprocessing right in the server and pass the final data on to the router and therequest handlers, which then can decide what to do with it.

Thus, the idea is to put the data and end event callbacks in the server, collectingall POST data chunks in the data callback, and calling the router upon receivingthe end event, while passing the collected data chunks on to the router, which inturn passes it on to the request handlers.

Here we go, starting with server.js:

var http = require("http");var url = require("url");

function start(route, handle) { function onRequest(request, response) { var postData = ""; var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");

request.setEncoding("utf8");

request.addListener("data", function(postDataChunk) { postData += postDataChunk; console.log("Received POST data chunk '"+ postDataChunk + "'."); });

request.addListener("end", function() {

Page 38: The Node Begineer Book

route(handle, pathname, response, postData); });

}

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

We basically did three things here: First, we defined that we expect the encodingof the received data to be UTF-8, we added an event listener for the "data" eventwhich step by step fills our new postData variable whenever a new chunk ofPOST data arrives, and we moved the call to our router into the end eventcallback to make sure it's only called when all POST data is gathered. We alsopass the POST data into the router, because we are going to need it in our requesthandlers.

Adding the console logging on every chunk that is received probably is a bad ideafor production code (megabytes of POST data, remember?), but makes sense tosee what happens.

I suggest playing around with this a bit. Put small amounts of text into thetextarea as well as lots of text, and you will see that for the larger texts, the datacallback is indeed called multiple times.

Let's add even more awesome to our app. On the /upload page, we will displaythe received content. To make this possible, we need to pass the postData on tothe request handlers, in router.js:

function route(handle, pathname, response, postData) { console.log("About to route a request for " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response, postData); } else { console.log("No request handler found for " + pathname); response.writeHead(404, {"Content-Type": "text/plain"}); response.write("404 Not found"); response.end(); }}

exports.route = route;

Page 39: The Node Begineer Book

And in requestHandlers.js, we include the data in our response of the uploadrequest handler:

function start(response, postData) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" content="text/html; '+ 'charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" method="post">'+ '<textarea name="text" rows="20" cols="60"></textarea>'+ '<input type="submit" value="Submit text" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

function upload(response, postData) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("You've sent: " + postData); response.end();}

exports.start = start;exports.upload = upload;

That's it, we are now able to receive POST data and use it in our request handlers.

One last thing for this topic: what we pass on to the router and the requesthandlers is the complete body of our POST request. We will probably want toconsume the individual fields that make up the POST data, in this case, the valueof the text field.

We already read about the querystring module, which assists us with this:

var querystring = require("querystring");

function start(response, postData) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" content="text/html; '+

Page 40: The Node Begineer Book

'charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" method="post">'+ '<textarea name="text" rows="20" cols="60"></textarea>'+ '<input type="submit" value="Submit text" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

function upload(response, postData) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("You've sent the text: "+ querystring.parse(postData).text); response.end();}

exports.start = start;exports.upload = upload;

Well, for a beginner's tutorial, that's all there is to say about handling POST data.

Handling file uploads

Let's tackle our final use case. Our plan was to allow users to upload an imagefile, and display the uploaded image in the browser.

Back in the 90's this would have qualified as a business model for an IPO, today itmust suffice to teach us two things: how to install external Node.js libraries, andhow to make use of them in our own code.

The external module we are going to use is node-formidable by FelixGeisendörfer. It nicely abstracts away all the nasty details of parsing incomingfile data. At the end of the day, handling incoming files is "only" about handlingPOST data - but the devil really is in the details here, and using a ready-madesolution makes a lot of sense in this case.

In order to make use of Felix' code, the according Node.js module needs to beinstalled. Node.js ships with its own package manager, dubbed NPM. It allows usto install external Node.js modules in a very convenient fashion. Given a workingNode.js installation, it boils down to issuing

Page 41: The Node Begineer Book

npm install formidable

on our command line. If the following output ends with

npm info build Success: [email protected] ok

then we are good to go.

The formidable module is now available to our own code - all we need to do isrequiring it just like one of the built-in modules we used earlier:

var formidable = require("formidable");

The metaphor formidable uses is that of a form being submitted via HTTP POST,making it parseable in Node.js. All we need to do is create a new IncomingForm,which is an abstraction of this submitted form, and which can then be used toparse the request object of our HTTP server for the fields and files that weresubmitted through this form.

The example code from the node-formidable project page shows how thedifferent parts play together:

var formidable = require('formidable'), http = require('http'), sys = require('sys');

http.createServer(function(req, res) { if (req.url == '/upload' && req.method.toLowerCase() == 'post') { // parse a file upload var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { res.writeHead(200, {'content-type': 'text/plain'}); res.write('received upload:\n\n'); res.end(sys.inspect({fields: fields, files: files})); }); return; }

// show a file upload form res.writeHead(200, {'content-type': 'text/html'});

Page 42: The Node Begineer Book

res.end( '<form action="/upload" enctype="multipart/form-data" '+ 'method="post">'+ '<input type="text" name="title"><br>'+ '<input type="file" name="upload" multiple="multiple"><br>'+ '<input type="submit" value="Upload">'+ '</form>' );}).listen(8888);

If we put this code into a file and execute it through node, we are able to submit asimple form, including a file upload, and see how the files object, which is passedto the callback defined in the form.parse call, is structured:

received upload:

{ fields: { title: 'Hello World' }, files: { upload: { size: 1558, path: '/tmp/1c747974a27a6292743669e91f29350b', name: 'us-flag.png', type: 'image/png', lastModifiedDate: Tue, 21 Jun 2011 07:02:41 GMT, _writeStream: [Object], length: [Getter], filename: [Getter], mime: [Getter] } } }

In order to make our use case happen, what we need to do is to include the form-parsing logic of formidable into our code structure, plus we will need to find outhow to serve the content of the uploaded file (which is saved into the /tmp folder)to a requesting browser.

Let's tackle the latter one first: if there is an image file on our local hardrive, howdo we serve it to a requesting browser?

We are obviously going to read the contents of this file into our Node.js server,and unsurprisingly, there is a module for that - it's called fs.

Let's add another request handler for the URL /show, which will hardcodinglydisplay the contents of the file /tmp/test.png. It of course makes a lot of sense tosave a real png image file to this location first.

We are going to modify requestHandlers.js as follows:

Page 43: The Node Begineer Book

We are going to modify requestHandlers.js as follows:

var querystring = require("querystring"), fs = require("fs");

function start(response, postData) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" '+ 'content="text/html; charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" method="post">'+ '<textarea name="text" rows="20" cols="60"></textarea>'+ '<input type="submit" value="Submit text" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

function upload(response, postData) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("You've sent the text: "+ querystring.parse(postData).text); response.end();}

function show(response, postData) { console.log("Request handler 'show' was called."); fs.readFile("/tmp/test.png", "binary", function(error, file) { if(error) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(error + "\n"); response.end(); } else { response.writeHead(200, {"Content-Type": "image/png"}); response.write(file, "binary"); response.end(); } });}

exports.start = start;exports.upload = upload;exports.show = show;

We also need to map this new request handler to the URL /show in file index.js:

var server = require("./server");var router = require("./router");var requestHandlers = require("./requestHandlers");

Page 44: The Node Begineer Book

var handle = {}handle["/"] = requestHandlers.start;handle["/start"] = requestHandlers.start;handle["/upload"] = requestHandlers.upload;handle["/show"] = requestHandlers.show;

server.start(router.route, handle);

By restarting the server and opening http://localhost:8888/show in the browser,the image file saved at /tmp/test.png should be displayed.

Fine. All we need to do now is

add a file upload element to the form which is served at /start,

integrate node-formidable into the upload request handler, in order to savethe uploaded file to /tmp/test.png,

embed the uploaded image into the HTML output of the /upload URL.

Step 1 is simple. We need to add an encoding type of multipart/form-data to ourHTML form, remove the textarea, add a file upload input field, and change thesubmit button text to "Upload file". Let's do just that in file requestHandlers.js:

var querystring = require("querystring"), fs = require("fs");

function start(response, postData) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" '+ 'content="text/html; charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" enctype="multipart/form-data" '+ 'method="post">'+ '<input type="file" name="upload">'+ '<input type="submit" value="Upload file" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

function upload(response, postData) { console.log("Request handler 'upload' was called.");

Page 45: The Node Begineer Book

response.writeHead(200, {"Content-Type": "text/plain"}); response.write("You've sent the text: "+ querystring.parse(postData).text); response.end();}

function show(response, postData) { console.log("Request handler 'show' was called."); fs.readFile("/tmp/test.png", "binary", function(error, file) { if(error) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(error + "\n"); response.end(); } else { response.writeHead(200, {"Content-Type": "image/png"}); response.write(file, "binary"); response.end(); } });}

exports.start = start;exports.upload = upload;exports.show = show;

Great. The next step is a bit more complex of course. The first problem is: wewant to handle the file upload in our upload request handler, and there, we willneed to pass the request object to the form.parse call of node-formidable.

But all we have is the response object and the postData array. Sad panda. Lookslike we will have to pass the request object all the way from the server to therouter to the request handler. There may be more elegant solutions, but thisapproach should do the job for now.

And while we are at it, let's remove the whole postData stuff in our server andrequest handlers - we won't need it for handling the file upload, and it even raisesa problem: we already "consumed" the data events of the request object in theserver, which means that form.parse, which also needs to consume those events,wouldn't receive any more data from them (because Node.js doesn't buffer anydata).

Let's start with server.js - we remove the postData handling and therequest.setEncoding line (which is going to be handled by node-formidableitself), and we pass request to the router instead:

var http = require("http");

Page 46: The Node Begineer Book

var http = require("http");var url = require("url");

function start(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received."); route(handle, pathname, response, request); }

http.createServer(onRequest).listen(8888); console.log("Server has started.");}

exports.start = start;

Next comes router.js - we don't need to pass postData on anymore, and insteadpass request:

function route(handle, pathname, response, request) { console.log("About to route a request for " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response, request); } else { console.log("No request handler found for " + pathname); response.writeHead(404, {"Content-Type": "text/html"}); response.write("404 Not found"); response.end(); }}

exports.route = route;

Now, the request object can be used in our upload request handler function.node-formidable will handle the details of saving the uploaded file to a local filewithin /tmp, but we need to make sure that this file is renamed to /tmp/test.pngourselves. Yes, we keep things really simple and assume that only PNG imageswill be uploaded.

For now, fs.renameSync(path1, path2) will do the job. Beware! As the nameimplies, it works synchronous, thus if the rename operation should be expensiveand take a long time, it will lead to blocking. Let's just agree that we are allgrown-ups here and know what we are doing.

Let's put the pieces of managing the uploaded file and renaming it together now,in file requestHandlers.js:

Page 47: The Node Begineer Book

var querystring = require("querystring"), fs = require("fs"), formidable = require("formidable");

function start(response) { console.log("Request handler 'start' was called.");

var body = '<html>'+ '<head>'+ '<meta http-equiv="Content-Type" content="text/html; '+ 'charset=UTF-8" />'+ '</head>'+ '<body>'+ '<form action="/upload" enctype="multipart/form-data" '+ 'method="post">'+ '<input type="file" name="upload" multiple="multiple">'+ '<input type="submit" value="Upload file" />'+ '</form>'+ '</body>'+ '</html>';

response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

function upload(response, request) { console.log("Request handler 'upload' was called.");

var form = new formidable.IncomingForm(); console.log("about to parse"); form.parse(request, function(error, fields, files) { console.log("parsing done"); fs.renameSync(files.upload.path, "/tmp/test.png"); response.writeHead(200, {"Content-Type": "text/html"}); response.write("received image:<br/>"); response.write("<img src='/show' />"); response.end(); });}

function show(response) { console.log("Request handler 'show' was called."); fs.readFile("/tmp/test.png", "binary", function(error, file) { if(error) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(error + "\n"); response.end(); } else { response.writeHead(200, {"Content-Type": "image/png"}); response.write(file, "binary"); response.end(); } });}

exports.start = start;exports.upload = upload;exports.show = show;

And that's it. Restart the server, and the complete use case will be available.

Page 48: The Node Begineer Book

And that's it. Restart the server, and the complete use case will be available.Select a local PNG image from your hardrive, upload it to the server, and have itdisplayed in the web page.

Conclusion and outlookCongratulations, our mission is accomplished! We wrote a simple yet full-fledgedNode.js web application. We talked about server-side JavaScript, functionalprogramming, blocking and non-blocking operations, callbacks, events, custom,internal and external modules, and a lot more.

Of course, there's a lot of stuff we did not talk about: how to talk to a database,how to write unit tests, how to create external modules that are installable viaNPM, or even something simple like how to handle GET requests.

But that's the fate of every book aimed at beginners - it can't talk about everysingle aspect in every single detail.

The good news is, the Node.js community is extremly vibrant (think of an ADHDkid on caffeine, but in a positive way), which means there are a lot of resourcesout there, and a lot of places to get your questions answered. The Node.jscommunity wiki and the NodeCloud directory are probably the best startingpoints for more information.

This document was last updated on Sunday, July 10, 2011 at 3:52 AM EDT.

The best way to stay informed about updates is to follow @ManuelKiessling on Twitter.

Page 49: The Node Begineer Book

Like

Sort by newest first

The Node Beginner Book is and will always be available for free. Furthermore, no money is needed to keep the project alive and progressing.

But if you would like to support the author, you can do so using Flattr or PayPal:

25

Or, have a look at the eBook version (Kindle, ePub, PDF), which is available for $4.99 via Leanpub.

Showing 216 comments

and 28 others liked this.

LoginAdd New Comment

Page 50: The Node Begineer Book

Excellent write up. But what do you think about this? http://www.usenix.org/events/h...

bcs

Like Reply5 days ago

So have you written a more full book on all the various aspects ofNode.JS? I am seriously willing to pay a good amount for it!

Shaan Batra

Like Reply1 week ago

Hi Shaan,

you might want to consider buying the Node.js bundle we arecurrently offering - it's The Node Beginner Book plus Hands-OnNode.js by Pedro Teixeira. The latter one is definitely a "full" bookcovering all the ins and outs of Node.js.

The bundle is for sale on LeanBundle.com, for$7.99: http://leanbundle.com/b/node

Manuel Kiessling

Like Reply1 week ago in reply to Shaan Batra 1 Like

Perfect. Will go ahead and purchase that. Thanks!

Shaan Batra

Like Reply1 week ago in reply to Manuel Kiessling

I would also like to purchase one...

Affiliate Tom

Like Reply1 week ago in reply to Shaan Batra 1 Like

That's great! Just have a look at

Manuel Kiessling

Page 51: The Node Begineer Book

http://leanpub.com/nodebeginne...

Like Reply1 week ago in reply to Affiliate Tom

Me too...

Sky Sports

Like Reply1 week ago in reply to Affiliate Tom

I am a QA engineer and I first started to use JavaScript withTestComplete. As it was its M$ version -- JScript I studied MSDN (I amso sorry... I'll never do so, I promise). The documentation was really awfuland I thought that the language is the same. Manuel, you changed mymind! Thank you very much for that.

Dzmitry Krakadzeyau

Like Reply3 weeks ago 1 Like

JScript is actually not that bad in all the ways that would count inNode.js. They've been ECMA compliant for a good decade now. Itwas the 10 years MS had been ignoring the W3C DOM API specthat was infuriating. I speak in the past tense because I thinkthey're finally starting to shape up a bit.

Erik Reppen

Like Reply3 weeks ago in reply to Dzmitry Krakadzeyau 1 Like

I do agree with you mate...

Bangladesh

Like Reply1 week ago in reply to Erik Reppen

Maybe, maybe... But their official documentation is repulsive.In addition TestComplete restricts JScript functionality so weneeded to do tricks sometimes. I want to say that my firstconclusion was incorrect. I could not simply get a goodimpression regarding JavaScript before. But this article did it.

Dzmitry Krakadzeyau

Page 52: The Node Begineer Book

Like Reply3 weeks ago in reply to Erik Reppen 1 Like

I got all the way to the end and ran into a problem on the last step. I'mgetting an error: "ENDENT, No such file or directory'/tmp/6f0320a3b21c779bb96af56abb843318'". The only line in my codethat is referenced in the stack trace is the"fs.renameSync(files.upload.path, "tmp/test.png")" ... any ideas whatI've done wrong??

Mike

Like Reply3 weeks ago

Mike, it seems you forgot a slash in "/tmp/test.png".

Dzmitry Krakadzeyau

Like Reply2 weeks ago in reply to Mike 1 Like

Thanks for the tutorial, best one so far on node.js!

BTW, I think you can rewrite some parts, such as: -

For the handle object could use as object literal,

var handle = { "/": requestHandlers.start//etc..};

Also the section with the delayed response

var exec = require("child_process").exec;function start(response) { console.log("Request handler 'start' was called.");

exec("find /", { timeout: 10000, maxBuffer: 20000*1024 }, function (error, stdout, stderr) {

Zawaung

Page 53: The Node Begineer Book

response.writeHead(200, {"Content-Type": "text/plain"}); response.write(stdout); response.end(); });}function upload(response) { console.log("Request handler 'upload' was called."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello Upload"); response.end();}

exports.start = start;exports.upload = upload;You could use setTimeout,setTimeout(function () {response.writeHead(200, {"Content-Type": "text/plain"});response.write('yup');response.end();},10000); Then no need for child_process require.What you think?

Like Reply3 weeks ago

just ignore the last part, not reading the page properly, Doh!

Zawaung

Like Reply3 weeks ago in reply to Zawaung

Hi. So first of all thank you very much for investing the time and effort indoing this. I do have one question

"var body = ''+ ''+ '<meta '+<br="" http-equiv="Content-Type"> 'content="text/html;charset=UTF-8" />'+ ''+ ''+ '<form action="/upload" method="post">'+ '<textarea cols="60" name="text" rows="20"></textarea>'+ '<input type="submit" value="Submit text">'+ ''+

Oscar Villarreal

Page 54: The Node Begineer Book

''+ '';"Instead of doing this can we say use a template file in the back endwhere we "clone" or something of a kind that html and then send it?Thanks!</form>

Like Reply4 weeks ago

Thank you. It was helpful to introduce to node.js.

Selçuk Yavuz

Like Reply1 month ago

It is vary perfect tutorial for me!!Thank you!

I have a question : on the non-blocking part the result of "ls" can't showon the web page ,but it can be showed on console.log()

Maybe I didn't understand.

baobaoyeye

Like Reply1 month ago

Hey, loved this tutorial, great style, great depth, very impressive, welldone.

For the sake of giving some constructive feedback (I know it's just anexample) but I'm surprised that the handle object is in index. In playingabout, I moved it to the router and called it routes, which makes routerjust about routing and keeps index clean (and fits with some phpframeworks).

Anyway, awesome job, thanks for your time, good luck with the book.

theade

Like Reply1 month ago

Hi Manuel,

Prince Nishchal N E

Page 55: The Node Begineer Book

It's a very nice and elegant tutorial to Node Beginners. Thanks forposting the tutorial

Like Reply1 month ago 1 Like

Thanks for the absolutely wonderful introduction to node.js! Whileworking through the tutorial, I had one question:

1. In our final editing of the request handlers, we reduced both the 'start'and 'show' handlers to only accept one function parameter (response),while the 'upload' handler still accepts two parameters (response,request).

In the router code, however, we are blindly passing in two parameters towhichever handler gets called:

handle[pathname](response,request);

Is this a feature of JS that allows you to pass in the incorrect number ofparams? If so, it certainly makes our router code cleaner, but it also maycause some confusion. Since the code is working, I'm assuming that JSgracefully handles this by just using the first parameter in both the 'start'and 'show' cases.

Any clarification here would be great!

Thanks again for the wonderful work!

Tom Hauburger

Like Reply1 month ago 2 Likes

JS allows handling params based on the function that is beingcalled. In this case since the start and show have only one inputparameter in their functions, the other parameter is omitted by theJS Engine. It is safe to pass any number of parameters in thefunction calls and JS handles this gracefully. However there will besome confusion to the developers initially who are new to JS way of

Prince Nishchal N E

Page 56: The Node Begineer Book

mapping parameters and function overloading.

Like Reply1 month ago in reply to Tom Hauburger 1 Like

While the code is functional and working without problems,just as Prince Nushchal N E explained, it might be a goodidea to add a note elaborating on function overloading to thebook's text. I will do this as soon as I have the time.

Manuel Kiessling

Like Reply1 month ago in reply to Prince Nishchal N E

Awesome. Thanks for the response!

Tom Hauburger

Like Reply1 month ago in reply to Manuel Kiessling

Great tutorial! Thanks a ton.

brandontreb

Like Reply1 month ago 1 Like

I'm a Happy Panda after reading this, :@ ) fantastic work and great tutor.

Paul Rogers

Like Reply1 month ago 1 Like

Thanks alot!

LIor

Like Reply1 month ago 1 Like

really nice! helped a lot

gradinariu bogdan

Like Reply1 month ago 1 Like

Jab

Page 57: The Node Begineer Book

Thank you ! You are my hero !

/Yossi.

Like Reply1 month ago 1 Like

Bought the bundle yesterday. Read your book last night. I really likeyour writing style. And the example project you picked to build wasperfect. I also thought the pace of the project progression (say that 3times fast!) was spot-on. After seeing all the buzz about node.js, butnever taking the time to understand what all the buzz was about, I feellike I now "get" why people are so excited.

I would definitely buy any books you write in the future, so keep 'emcoming!

Jamey Cribbs

Like Reply1 month ago 1 Like

Hi Jamey,

thanks for your encouraging answer! I'm happy to hear that thepace is okay - it's extremely difficult to know if the pace is ok if youare the author.

Manuel Kiessling

Like Reply1 month ago in reply to Jamey Cribbs

Great tutorial Manuel! I like your writing style, the example, and yourfunctional implementation.

In the spirit of functional programming, I offer two other options thatothers may find useful:

pkazmier

Page 58: The Node Begineer Book

(i) Change the implementation of 'route' to return the request handlerfunction, then execute that function within 'onRequest'. The benefits ofthis approach is that the routing module performs only routing, whichmeans the 'request' and 'response' objects don't have to be passedthrough to the router. Routing and request handling are then trulyseparate and allowing the possibility of alternate execution strategies.

(ii) Change the implementation of 'route' module so that 'handle' doesn'thave to be passed to the server only to be passed to the route function. Iagree with staii's comment (far below) about the alternate approaches:(a) object-oriented approach of passing the route object instead of aroute function, or (b) keeping with the functional approach, pass thehandle array to the route module that creates a custom route functionusing a closure.

After implementation both of these suggestions, the route module is usedstrictly for routing and not the execution of request handlers, while at thesame time simplifying the route function as it would now only require asingle argument: function route(pathname).

Again, fantastic tutorial, well written, and nice to introduction to node.js,which I've been meaning to read about for some time now.

Like Reply1 month ago 1 Like

Hey Manuel,

Great tutorial!The following lines appear multiple times and I believe "err" should be"error".

if(error) { response.writeHead(500, {"Content-Type": "text/plain"}); response.write(err + "\n");

Edit: Oops, seems like Mark Sost beat me to it!

Dan Kang

Like Reply1 month ago 1 Like

Page 59: The Node Begineer Book

Dan, Mark, thanks a million! I'll fix it asap.

Manuel Kiessling

Like Reply1 month ago in reply to Dan Kang

Fixed with https://github.com/ManuelKiess... and updatedthe site.

Thanks once again!

Manuel Kiessling

Like Reply1 month ago in reply to Manuel Kiessling

No problem, once again, great job!

Mark Sost

Like Reply1 month ago in reply to Manuel Kiessling

Hey Manuel, not sure if someone else noted, but there's a typo in theshow requestHandler function. response.write(err + "\n"); should actuallybe response.write(error, "\n"); within the if(error) case. Great tutorial,though! Learned a lot from it!

Mark Sost

Like Reply1 month ago 1 Like

Hey Manuel *great work*! Two notes, though: it's not quite true that NPM«ships with node». It has to be installed apart. And I'd have added somemore thoughts about another important characteristic of Node that youglissed a little (maybe because it's quite "advanced stuff"). I mean the«because Node.js doesn't buffer any data» part.Thank you again

Claudio Cicali

Like Reply1 month ago 2 Likes

Manuel Kiessling

Page 60: The Node Begineer Book

Hi Claudio,

thanks for the input. I will improve these parts. Can you elaborateon the data buffering?

Like Reply1 month ago in reply to Claudio Cicali

The point is that the fact that node doesn't buffer anythingmakes it a nice tool for people trying to build something nastywith streams (like enconding/converting while uploading ordownloading). Anyway, as I mentioned, it could be slighlty OTof the purpose of the book.

Claudio Cicali

Like Reply1 month ago in reply to Manuel Kiessling

Is the complete source code available somewhere?

bought the pdf

Like Reply1 month ago 1 Like

Yes, it is, at https://github.com/ManuelKiess...

I will put that link into the book, too!

Manuel Kiessling

Like Reply1 month ago in reply to bought the pdf

Hey, guys read http://learnyousomeerlang.com/ first xD

Сергей

Like Reply1 month ago

Great tutorial!

One small problem - this line in the last bit: response.write("You've sent the text: " + querystring.parse(postData)

Eric Danielson

Page 61: The Node Begineer Book

["text"]);didn't work for me - had to be: response.write("You've sent the text: " +querystring.parse(postData).text);

Otherwise, everything else was awesome - Thanks!

Like Reply2 months ago 1 Like

Hi Eric,

I've fixed this with https://github.com/ManuelKiess...

Thanks once again!

Manuel Kiessling

Like Reply2 months ago in reply to Eric Danielson

Thanks for the hint! I'll look into it.

Manuel Kiessling

Like Reply2 months ago in reply to Eric Danielson

Great tutorial! I have to agree with PING, though. :) Can you give us aballpark of around when the rest will be posted? Tomorrow? Next week?Next month? Thanks.

Bob

Like Reply2 months ago 1 Like

Hi Bob,

I've released the final version of the eBook on my publisher's site,http://leanpub.com/nodebeginne...

It contains the final chapter on handling file uploads. The websitewill be updated soon, but until then, you can buy the eBook for only

Manuel Kiessling

Page 62: The Node Begineer Book

$3.99 instead of $4.99 by using the coupon code"FirstAccessForCommentReaders" on Leanpub.

Like Reply2 months ago in reply to Bob

Coupon code expired or invalid

Josue Gio

Like Reply1 month ago in reply to Manuel Kiessling

That's true, it was only a limited offer.

There is a bundle offer overat http://leanbundle.com/bundles/... - "The NodeBeginner Book" plus "Hands-on Node.js" for only $7.99instead of $10.98

Manuel Kiessling

Like Reply1 month ago in reply to Josue Gio

It's awesome to see so much interested, thanks! I think next weekshould be feasible!

Manuel Kiessling

Like Reply2 months ago in reply to Bob

I don't want to be a pest, but please post more soon! I have plans touse node formidable, so I'm eagerly awaiting the next chapter.

PlNG

Like Reply2 months ago 1 Like

Hi PING,

I've released the final version of the eBook on my publisher's site,http://leanpub.com/nodebeginne...

Manuel Kiessling

Page 63: The Node Begineer Book

It contains the final chapter on handling file uploads. The websitewill be updated soon, but until then, you can buy the eBook for only$3.99 instead of $4.99 by using the coupon code"FirstAccessForCommentReaders" on Leanpub.

Like Reply2 months ago in reply to PlNG

Coupon code expired

Drew Wells

Like Reply1 month ago in reply to Manuel Kiessling

Yes, i'm afraid that was only a temporary offer.

Manuel Kiessling

Like Reply1 month ago in reply to Drew Wells

The final version is close to being finished, promised!

Manuel Kiessling

Like Reply2 months ago in reply to PlNG

Awesome tutorial ... thanks much!

Michael Rand

Like Reply2 months ago 1 Like

Seriously the only tutorial that has helped me as a beginner to node.js. Great work! And please, please release more on more advanced topicsif you can.

Erik

Like Reply2 months ago 1 Like

Great Job !!! I've written on my blog several articles (in French) aboutnode.js :feel free to leave me comments :)

Vincent RABAH …, DSI, blogueur★Passionné de scalabilité,Green IT,virtualisation VMware,résea

Page 64: The Node Begineer Book

http://www.it-wars.com/?articl...http://www.it-wars.com/?articl...http://www.it-wars.com/?articl...http://www.it-wars.com/?articl...

Regards !

Like Reply2 months ago

This is brilliant. Also, have you publicized your bookmarks list? :)

seshness

Like Reply2 months ago 2 Likes

Great stuff. Very well explained. Loved the linked articles too!

Diego

Like Reply2 months ago 1 Like

Excellent!

Dev

Like Reply2 months ago 1 Like

Thanks a lot for this useful and complex tutorial :)

I'm a absolute beginner with node.js (and javascript as such), but Ihaven't found 1 thing. How could you do cross-domain requests fromserver-side? Lets say user want to see some photo, send request tonode.js and I want to make GET request to some web service. I'mswitching from java so maybe I'm just missing something.

Vladimír Říha

Like Reply2 months ago 1 Like

The http module can make get requests. Check the docs for more

Craig

Page 65: The Node Begineer Book

info.

Like Reply3 weeks ago in reply to Vladimír Říha

jQuery has some methods to enable cross-domain requests:

http://api.jquery.com/jQuery.g...

Herman A. Junge

Like Reply2 months ago in reply to Vladimír Říha 2 Likes

Amazing. So helpful and your approach is very easy to read. Thanks somuch! Just bought the book and am anxiously looking forward to theuploads and images section.

SUGGESTION: maybe set up a system to allow donations for bountiesfor future works after you finish this book. For example, I'd donate to up-vote adding a chapter on creating a template system for our router fromthis tutorial.

Patrick Mazzotta

Like Reply2 months ago 1 Like

I'll think about this, it's a good idea!

Manuel Kiessling

Like Reply2 months ago in reply to Patrick Mazzotta

Great tutorial, thanks, I would also like to see a tutorial on how to tie inmongoDB with node.js and have JS power virtually everything.

John Isaacks

Like Reply2 months ago 1 Like

I'd just be adding to what everyone else has said. Great tutorial Manuel.

Je_suis_un_sheepdog

Like Reply3 months ago 1 Like

Page 66: The Node Begineer Book

As I previously wrote, this is a great tutorial. Thanks!

What I find missing is that the server is not fully operational as a webserver. I've added a function that changes the content type of theresponse with regards to the file being returned: HTML, CSS, JS, etc.

However I don't know how to have a default "handle" routing in index.js.What I would like to do is make the last handle route any un-handledrequests to my web server function. This way, if I use my browser to getlocalhost/index.html, it will be handled correctly, including css and js.

Any ideas?

Idophir

Like Reply3 months ago

Great read, looking forward to the end :)

Thor Erik

Like Reply3 months ago 1 Like

Awesome tutorial! Finally understood the advantages and core conceptsbehind node.js and functional programming. Thanks a lot!

Helge

Like Reply3 months ago 1 Like

Absolutely Excellent Tutorial!

S&S Network Solutions

Like Reply3 months ago 1 Like

Amazing, can't wait for the end! Keep the fun.

Pedro Henrique Fialho

Like Reply3 months ago 1 Like

crocodile

Page 67: The Node Begineer Book

Great tutorial, just finished it...keep them coming

Like Reply3 months ago 2 Likes

Thank you for the tutorial, I've been looking for a clear explanation of howto get started with node.js - I'm actually really very seriously consideringmoving my current project over to node.js from php after reading this andthe links you've provided, it seems to be a better fit!Thanks again ^_^

Brendan O'Connor

Like Reply3 months ago 1 Like

Hi Brendan,

I would love to hear about your experience should you really moveyour project to Node.js - and your reasons if you don't do it!

Manuel Kiessling

Like Reply3 months ago in reply to Brendan O'Connor 1 Like

Dude - you pretty much nailed it. I'm an elearning developer by trade,and in practice obviously an avid googler/stackoverflower/etc/etc, thistutorial intro to Node.js is not only a tribute to Node.js, but also a veryfine piece of tech learning in general. Well done, thank you, and bestwishes in completing whatever you feel you need to complete.

- danjah / novice-come-advanced-novice

David J Wallace

Like Reply3 months ago 1 Like

It's absolutely awesome to get this kind of feedback - thank youvery much!

I hope to write the final chapter real soon.

Manuel Kiessling

Page 68: The Node Begineer Book

Like Reply3 months ago in reply to David J Wallace

Outstanding! Thanks for taking the time to write this.

Chris Cummings

Like Reply3 months ago 1 Like

Hi all, just wanted to let you know that the book is now at 90%. I'veadded chapters on how to handle POST requests.

As you will notice, I've decided to sell an eBook version via Leanpub.

Manuel Kiessling

Like Reply3 months ago

I am not getting response body for POST and PUT request. bothrequest having body. code is given belowvar data = ""; req.setEncoding("utf8"); req.addListener("data", function(postDataChunk) { data += postDataChunk; AndroidLog.ReqStart("Contact POST = ", "Inside req.ondata"); });

req.addListener("end", function() { AndroidLog.ReqStart("Contact POST = ", "Inside req.onend"); res.writeHead(404, {"Content-Type": "text/html"}); res.write("404 Not found"); res.end(); });

response status is always 200 ok and no response body. I am usingmozila REST client.

Yudhisthira Attry

Like Reply1 month ago in reply to Manuel Kiessling

Page 69: The Node Begineer Book

Nicely done! Will be looking forward to your updates.

Eugene Geronimo

Like Reply3 months ago 1 Like

A small improvement: In the Routing to real request handlers chapter, you explain about therequestHandlers but do not instruct to start a new file(requestHandlers.js) for them.

Idophir

Like Reply3 months ago 2 Likes

Thanks mate, I'll have a look at it once I'm home. I'm currently onvacation, until next week.

Manuel Kiessling

Like Reply3 months ago in reply to Idophir

I have no words to express my thanks. I am a newb to back end codingbut been working with javascript for a while. This definitely opens up aworld of knowledge. If you ever write a book I'll buy it

Oscarvillarreal14

Like Reply3 months ago 2 Likes

Hi Manuel! This is really great. It's exactly what I had started doing on myown, by breaking apart express, but laid out in a much more logicalmanner.

One thing - I thought this line read a little clunkily:

... but because we learned the hard way from our experience with otherprogramming languages, we are going to loosely couple server androuter by *injection* this dependency ...

Minikomi

Page 70: The Node Begineer Book

perhaps should be

... but because we learned the hard way from our experience with otherprogramming languages, we are going to loosely couple server androuter by *injecting *this dependency ...

Eagerly awaiting the forthcoming parts!

Like Reply4 months ago 1 Like

Hi,

Thanks for reading NodeBeginner.

Andrew Gruner sent me a pull request today, fixing exactly thisissue:

https://github.com/ManuelKiess...

Please check if ctrl-reload shows you the updated version of thepage.

Manuel Kiessling

Like Reply4 months ago in reply to Minikomi

I just realized, the whole requestHandler thing is a bit redundant... This iswhat I use in my code at the moment, it's alot cleaner:

var handle = require('./handlers');--- handlers.js---

exports['/start'] = function (query,callback) {callback({responseCode:200}, 'Start');};

// equivalent to exports['notfound'] but it's not a path (there is no locationcalled notfound,) so there is no forward-slash, so I can use the dotnotation. (this function is called when a pathname is requested that's not

Arian van Putten

Page 71: The Node Begineer Book

in the handle objectexports.notfound = function(query,callback) {

}exports['/upload'] = function (query,callback) {callback({responseCode:200}, 'Not Implemented');};

(Edited by a moderator)

Like Reply4 months ago 3 Likes

Hi Arian,

I've edited your comment, because the h1 HTML tags wereinterpreted by Disqus and displayed as real h1 headlines on thepage, which broke the layout. I hope that's ok.

Regarding your code, that makes a lot of sense, I didn't know onecould use "exports" like this.

I will see how I can integrate that into the book.

Manuel Kiessling

Like Reply4 months ago in reply to Arian van Putten 1 Like

well, everything follows the JSON (Java Script ObjectNotation), even the exports object. the dot notation(object.property) is just syntax sugar for object['property']

Arian van Putten

Like Reply4 months ago in reply to Manuel Kiessling

Hi everyone, just wanted to let you know that it could take a while for meto find the time and write the missing 20% of the book - worst casewould be 2 weeks from now.

Problem is I currently have too many other stuff that needs to get done.

Manuel Kiessling

Page 72: The Node Begineer Book

Thanks for your support and your patience.

Like Reply4 months ago

It might be nice if you could make a list on the repository that sayswhat still has to be done, then maybe people can fork the project,work on those points on the list and then you can look at the forkedprojects if you see anything you might want to use in the final book.

Arian van Putten

Like Reply4 months ago in reply to Manuel Kiessling 1 Like

The favicon requests got annoying, you can easily ignore them though:

function start(route, handle) {function onRequest(request, response) {var pathname = url.parse(request.url).pathname;if (pathname != "/favicon.ico") { /* ignore all favicon.ico requests */console.log("Request for "+pathname+" received.");route(handle, pathname, response);} /* end if */}

http.createServer(onRequest).listen(8888);console.log("Server has started");}

Jak Spalding

Like Reply4 months ago 1 Like

Hi Jak,

thanks for the hint. I hesitated adding more complexity to the codeexamples than absolutely necessary, but I understand that theadditional requests showing up can be annoying. I will see if Iinclude your code in the examples.

Manuel Kiessling

Like Reply4 months ago in reply to Jak Spalding

Page 73: The Node Begineer Book

This is a wonderful guide. I've found it to be quite informative. Keep upthe great work!

blcArmadillo

Like Reply4 months ago 1 Like

This is probably one of the most amazing introductory guide to node.jsthat I have read yet! Amazing work, can't wait for the rest of the guide.This definitely gives me a starting point to jump into node.

When I finished reading the section "JavaScript and You" I knew thiswas going to be an amazing guide. Your description fit me perfectly,really amazing work.

Travis Person

Like Reply4 months ago 3 Likes

you can use curl and there will be no /favicon requests.

Guest

Like Reply4 months ago 2 Likes

Excellent, hope that you will continue with this.

Neiliss

Like Reply4 months ago 1 Like

Excellent tutorial. Keep up the great work!

Rob Brazier

Like Reply4 months ago 2 Likes

Your are the greatest!

I finally found the time to install ubuntu on a spare laptop, added nodeand npm and started going through your well written book. I'm having fun

Idophir

Page 74: The Node Begineer Book

and I love how you make complicated things seem understandable.

I'm about half way through the book and had a question. What do youfeel about using frameworks such as "express" to handle most parts ofthe requests handling?

Like Reply4 months ago 1 Like

My very subjective opinion: I think using frameworks makes a lot ofsense!

Building everything up from zero for every project simply is tootedious. You have to put a lot of effort into infrastructure workinstead of putting this effort into what makes your project valuableto your users.

But building everything up from zero makes a lot of sense if youwant to learn a new technology. If you skip understanding the basisof a new technology and start using the frameworks built on thisbasis right away, then everything you learn from there on will beshallow.

It works ok and you might even be relatively productive, but youwill run into problems once you have to finish a project under timepressure, or if you need to find a solution for a problem theframeworks doesn't address.

That, on the other hand, doesn't mean you need to know andunderstand every single line of Express before using it. Butunderstanding the basic idea of these frameworks and theirmechanics makes a lot of sense.

I hope this tutorial can help you with this.

Manuel Kiessling

Like Reply4 months ago in reply to Idophir 1 Like

great great tutorial :) noticed a typo here "Our handler functions need to

sofia cardita

Page 75: The Node Begineer Book

accept the response parameter, and have to make use of them in orderto repsond to the request directly." - notice the "repsond"Thanks :) I was needing some input on how to better organize code innode and this was just the thing to fit the bill!

Like Reply4 months ago 1 Like

Hey, I really love http://onesandzeros.posterous...., especiallybecause I want to do something similar!

Manuel Kiessling

Like Reply4 months ago in reply to sofia cardita

Hi Sofia,

Thank you very much, I fixed the typo!

Manuel Kiessling

Like Reply4 months ago in reply to sofia cardita

great great tutorial :)

sofia cardita

Like Reply4 months ago 1 Like

Thanks a million for this article. I worked through it this morning and myonly concern was that you might lose interest and not complete it. But Icome back this evening and there is a huge update! Really excellent stuffand pitched at just the right level for me. Many thanks indeed.

Dominic Butler

Like Reply4 months ago 1 Like

Thanks! Rest assured I'm having the fun of my life and am not goingto loose interest anytime soon.

One question: Is it difficult to pick up the new content if you come

Manuel Kiessling

Page 76: The Node Begineer Book

back after an update happened? Especially if like today chaptersthat were already written are partly rewritten? Does the documentneed a clickable table of contents?

Like Reply4 months ago in reply to Dominic Butler

It probably should have a clickable table of contents. It wouldbe a nice to have.

Adrian Pomilio

Like Reply4 months ago in reply to Manuel Kiessling

Hi Adrian,

the site now has a table of contents - I hope you like it.

Manuel Kiessling

Like Reply4 months ago in reply to Adrian Pomilio

Wow. This is simply the best Getting Started with node.js for me. Thanks!

Nikhil Bafna

Like Reply4 months ago 1 Like

Good Sir, this was absolutely awesome! I was looking to betterunderstand node.js. Came across your article and was completely drawnin. Keep up the good work! Also, might I suggest leaving the Work InProgress notification up forever with whatever your next mini-goal is? Itwould serve to whet the reader's appetite further.

Savil Srivastava

Like Reply4 months ago 1 Like

It probably WILL be a neverending work in progress, simplybecause Node.js itself is.

Manuel Kiessling

Page 77: The Node Begineer Book

Like Reply4 months ago in reply to Savil Srivastava

Fantastic. Best beginner node tutorial I've come across yet.

Thanks for taking the time to explain in-depth the theory behind theworkings of node.js, instead of just telling me what stuff to type. :)

Seth Etter

Like Reply4 months ago 1 Like

I'm new to Web development, having recently learned HTML, CSS,Javascript and jQuery. I was feeling ready to build my first "real" webapp but didn't know if I should learn another language/framework (PHPor Ruby) and if so which one. I discovered your Book and am reallyexcited about using node.js instead. Your book has been hugelyinstructive. Thanks so much!

I hesitated to leave a comment as I see you reply to nearly all commentsand frankly I'd rather you spend your time working on the next part of the"Book" than thanking me for my comment. So hopefully you will. :-)

nketter

Like Reply4 months ago 1 Like

Haha, that's one cool comment! I promise I won't respond andinstead work... D'oh! :-)

Manuel Kiessling

Like Reply4 months ago in reply to nketter 1 Like

Superb to read!!

Vishal

Like Reply4 months ago 1 Like

This is an amazing tutorial. It manages to explain advanced (for a JSnovice like me) concepts in a very accessible way. Keep it up! And

Jsnovice

Page 78: The Node Begineer Book

please continue working on this :)

Like Reply4 months ago 1 Like

Greate work. Thanks!

Usubov

Like Reply4 months ago 1 Like

Like the way you tell the STORY. I will be back and read it.

hq

Like Reply4 months ago 1 Like

Just wanted to throw my thanks onto the pile. Cheers!

Ron Rieneckert

Like Reply4 months ago 1 Like

This is very helpful! Great job.In router.js line 3 "if (typeof handle[pathname] !== 'function')" shouldhave equal to rather than not equal to.

Tarun

Like Reply4 months ago

My bad, thanks for finding it!

I have fixed it and updated the page.

(just for the record: if you ever need to urgently fix your site, butyour notebook is in the room where your guests are sleeping,FTPOnTheGo for iPhone can help you out - an extremely well doneapp)

Manuel Kiessling

Like Reply4 months ago in reply to Tarun

Page 79: The Node Begineer Book

Now also fixed in the repository:https://github.com/ManuelKiess...

Manuel Kiessling

Like Reply4 months ago in reply to Manuel Kiessling

Thanks! That was blazing fast!

Tarun

Like Reply4 months ago in reply to Manuel Kiessling

Manuel,

First, thanks for putting this together! Really enjoy the flow and the brieftrips into the world of Javascript. Very helpful.

I'm currently learning CoffeeScript and really enjoying it. As such, Ithought I'd follow along with your examples, but write them inCoffeeScript instead. I've created a git repo over athttps://github.com/jackdempsey...

Hope that's alright with you. If you haven't done any CoffeeScript, youshould check it out!

Look forward to the next chapters.

Jack Dempsey, Developer, Entrepreneur, builder of things

Like Reply4 months ago

That's brilliant! I will definitely check it out as soon as possible(right now it's 11pm here and my wife demands I get some sleep...)

I love CoffeeScript, but decided to keep the tutorial plain JS inorder to not introduce too much at once.

I already planned to point the reader at CoffeeScript at the end ofthe tutorial, and I will definitely refer to your project.

Manuel Kiessling

Page 80: The Node Begineer Book

Like Reply4 months ago in reply to Jack Dempsey

Yeah, that makes a lot of sense. I'll try and clean the projectup and make sure it looks good at the end.

Jack Dempsey, Developer, Entrepreneur, builder of things

Like Reply4 months ago in reply to Manuel Kiessling 1 Like

Jack,

finally had a chance to take a look. Simply loving it!When the "main" book is finished I will add an "where togo from here" section, and will introduce CoffeeScriptthere. I will refer to your examples, and will also refer tothem in a yet-to-be-added "download the samplecode" section.

Thanks for investing your time!

Manuel Kiessling

Like Reply4 months ago in reply to Jack Dempsey

Great, happy to help.

Do you think it's worth tagging each stage ofbuilding the code so people can easily stepthrough things? I often just jump to the end resultand read over it instead.

Jack Dempsey, Developer, Entrepreneur, builder of things

Like Reply4 months agoin reply to Manuel Kiessling

Me too. I have seen people putting a lot ofeffort into creating repos this way, but Idon't believe it is used that often by readers,

Manuel Kiessling

Page 81: The Node Begineer Book

and thus not really worth it.

Like Reply4 months agoin reply to Jack Dempsey

Good job!

Just a small comment, passing your "handle object" to the server is not aclean abstraction. If I was doing this, I would either create an interfaceon the router to "register" handlers and their corresponding URLs, thenpass the router itself to the server (rather than passing the routefunction). Either that, or I would define a createRouter() function thattakes the "handle object", and returns a router function, saving theobject in a closure.

staii

Like Reply4 months ago

You are absolutely right. But the challenge is - at least I feel it is -to find the right balance regarding the example application.

Complex and interesting enough to be a valuable source forlearning and understanding, but not too complex and thereforehindering the reader from learning the stuff relevant for the tutorialby introducing stuff that is not relevant for the tutorial.

Which, of course, leads to the discussion about what should beconsidered relevant and what not, and I'm far from being sureabout that.

However, my gut feeling is that the current level of abstraction inthe application fits the purpose of learning Node.js quite well.

In the tutorial I could point out that more or different layers ofabstraction could make sense - but that's true for every part of theapp, which means I would need to point it out again and again, andthat might be annoying.

Manuel Kiessling

Page 82: The Node Begineer Book

The good thing is, is that your excellent observation is nowavailable in the comments, adding huge value to the tutorial.

If you're fine with that I suggest we keep it that way.

What's your opinion on this?

Like Reply4 months ago in reply to staii 1 Like

I see your point about finding a balance. Being the author, Ithink you have vision to tell what should go in, and what couldadd too much complexity. My comment was only meant as asuggestion.

I guess having my suggestion in the comments is fair enough:)

staii

Like Reply4 months ago in reply to Manuel Kiessling 1 Like

start() is only blocking because you included a blocking sleep() call.Without the sleep() call, it is non-blocking. However, "return"ing ratherthan using callbacks does prevent you from using non-blocking IO APIs,which I guess is your point.

Joel Plane

Like Reply4 months ago

Hi Joel,

You're absolutely right. I simplified too much here and I'm going torewrite that part the very way you explained it.

Thanks for helping me with this one!

Manuel Kiessling

Like Reply4 months ago in reply to Joel Plane

Joel Plane

Page 83: The Node Begineer Book

Forgot to say thanks for a great read. I really enjoyed it.

Like Reply4 months ago in reply to Manuel Kiessling

Augh, I was extremely disappointed to hit the end - I was on a roll! Itreally speaks for this tutorial that I still feel like doing more node.js aftergetting this far, and I'm looking forward to the next chapters! So manynice things to be said about this tutorial, thanks so much for sharing it!

Alex Zirbel

Like Reply4 months ago 1 Like

Hi Alex,

sorry for the "cliffhanger" :-)

I should probably point out at the very beginning that this is work inprogress.

However, really glad to hear you like it!

Manuel Kiessling

Like Reply4 months ago in reply to Alex Zirbel

As long as this doesn't turn into "Lost" I'll be very happy!

The guide's great, although I foolishly took time out of writingmy dissertation to have a go :-)

Jak Spalding

Like Reply4 months ago in reply to Manuel Kiessling

Excellent work....

Incaandmaya

Like Reply4 months ago 1 Like

Diego

Page 84: The Node Begineer Book

This article is awesome. Thanks and i'm waiting for the next chapters.Great job.

Like Reply4 months ago 2 Likes

Thank you, you are a freaking rock star for doing this. I am up andrunning and enjoying all the info!

Adrian Pomilio

Like Reply4 months ago 1 Like

thanks for putting this together!! keep it up. > finish.

Amul Patel

Like Reply4 months ago 1 Like

You might want to consider having the article become "How to write yourown express.js". That way one can grow their knowledge of node basedon first principles and yet understand what express is all about.

whozman

Like Reply4 months ago

This is one of the best tutorials I've read. As a former Java coder, I'vealways found JavaScript to be a black art, but you have really simplifiedthings with this tutorial. I'm looking forward to subsequent installments.Well done!

Erskine

Like Reply4 months ago 2 Likes

Hi Erskine,

thank you so much for taking the time and reading NodeBeginner.Can't even describe how much fun the whole project is thanks tocomments like yours!

Manuel Kiessling

Page 85: The Node Begineer Book

Like Reply4 months ago in reply to Erskine

Very nice work here. I've had trouble getting good info on codeorganization with Node, so this is exactly what I'm looking for.

Other comments have mentioned AJAX, which I'm sure you have inmind. Are you going to handle communicating with some persistence layer? I'dfind that helpful.

Pat Farrell

Like Reply4 months ago 1 Like

Hi Pat,

I'm currently planning to describe the example application back-to-front, with using only barebone node. With this, the main part of the"book" would then be finished.

However, building on that and - as someone called it - "branchingout", i.e. explaining stuff like socket.io, DB handling, AJAX etc.makes a lot of sense, and I'll definitely consider this.

Manuel Kiessling

Like Reply4 months ago in reply to Pat Farrell

I was looking for a something to kickstart my learning of node.js andyou've provided a great start. I'm looking forward to purchasing the finalcopy.

I also wanted to add that by putting up this early draft for review (a labeta software) you're crowdsourcing both the grammar and technicalreview, not to mention created a huge pre-publication buzz. I don't recallseeing that in tech book previously and it's truly genius, surpassed onlyby how well you receive the comments and subsequently commit theedits.

Brett_Freeman

Page 86: The Node Begineer Book

I'm looking forward to watching the project progress toward.completion.Excellent work so far and thanks for including us in the process!

Like Reply4 months ago 1 Like

Hi Brett,

can't thank you enough for the friendly review.

To be honest, calling the whole project The Node Beginner *Book*was a bit of a stretch - I want to provide a thorough and completeintroduction, but I'm not sure if the final product will deserve thename "book".

Which is why, at this point, I'm not planning to release the finalproduct as a real book (be it hardcopy or eBook) - it's just a funproject of mine, and I would like to keep it free under the creativecommons.

After all, I can assure you that comments like yours are a lot morerewarding than money.

Manuel Kiessling

Like Reply4 months ago in reply to Brett_Freeman 1 Like

If you're not going to publish I'd like to recommend a tip jar.I'm sure there are many others like me who would gladly kickin $5 - $10 in support of this fine effort.

Brett_Freeman

Like Reply4 months ago in reply to Manuel Kiessling 3 Likes

+1 on the idea of a tip jar. I'd definitely kick in US $5 -$10 as well.

Alan Hecht, Software Developer living in Atlanta, GA

Like Reply4 months ago in reply to Brett_Freeman2 Likes

Page 87: The Node Begineer Book

Brett, Alan,

you guys are awesome, what can I say? I hopethe project isn't compromised in any way by it,but I added a Flattr button (right above thecomments).

Check it out and tell me what you think.

Manuel Kiessling

Like Reply4 months ago in reply to Alan Hecht2 Likes

Looks good. I don't think it wouldcompromise what you're doing since it'sentirely voluntary and pretty innocuous

Alan Hecht, Software Developer living in Atlanta, GA

Like Reply4 months agoin reply to Manuel Kiessling 1 Like

^_^ <3

Henry Allen-Tilford

Like Reply4 months ago 1 Like

I just finished reading the tutorial and can't wait until you put some morematerial. I haven't had the faintest idea about node.js before and I reallylike the build-up process which eventually leads to a full blown web app.Nice work and keep it up! Cheers!

Dananjaya

Like Reply4 months ago 1 Like

Hi Dananjaya,

Manuel Kiessling

Page 88: The Node Begineer Book

I'm glad you like it, that really keeps me going. If you find errors orthink that parts of the text are not as good as you think they couldbe, please let me know!

Like Reply4 months ago in reply to Dananjaya 1 Like

I too am making the transition from "novice" to "advanced novice" and Iwas thinking about writing some blog posts on it, but I am far morepleased with what you're doing here. I'd gladly trade notes with you,especially once you get into more advanced topics. I'm currently usingnode, express and mongoose to make a beta signup page. I'm on thefinal step of dumping the email address into a MongoDB database viamongoose but struggling mightily with it. I definitely would suggestcovering all of the basics in just node, and then branching out into thebudding framework ecosystem such as express and talking about howthese core concepts are implemented there. For example, Express has areally strong routing engine but it's definitely worth it to see how that isimplemented from the ground up before having a framework handle it foryou.

Matthew Case

Like Reply4 months ago 3 Likes

Hi Matthew,

I have to admit that I haven't worked with Express and Mongooseyet. Once the basic introduction on how to build a full blown appwith barebone node is finished, it makes a lot of sense to talk aboutFrameworks and databases, so yes, I would really love to hear yourideas and share notes. You can fork the document on Github atany time and send me your changes as pull requests:https://github.com/ManuelKiess...

Of course you can also simply drop me a line in the comments or [email protected]

Looking forward to it!

Manuel Kiessling

Page 89: The Node Begineer Book

Like Reply4 months ago in reply to Matthew Case 1 Like

This is such a great guide. I can't wait to finish reading it. Keep up thegreat work.

Justin Herrick

Like Reply4 months ago 1 Like

Hi Justin,

I'm really happy you like it. I intend to add new chapters every day,I hope it works out!

Manuel Kiessling

Like Reply4 months ago in reply to Justin Herrick

Excellent nodejs begginer tutorial ... Router part is done on the mostelegant way! Do you have plan to explain socket.io too?

Darko Bunic

Like Reply4 months ago 1 Like

I haven't played around with socket.io yet, thus my answer is"maybe". Of course, socket.io (arguably) isn't "beginner", which iswhy it probably wouldn't fit here.

Manuel Kiessling

Like Reply4 months ago in reply to Darko Bunic

Nice tutorial. node.js is really a quick way to realize small web projects.Unfortunately like every dynamic typed language not usable for bigbusiness projects cause of the lack of supporting refactoring andcompile time checking like static languages.http://beust.com/weblog/2006/1...

Ronny Bubke

Like Reply4 months ago

Page 90: The Node Begineer Book

With "not usable" you mean not usable like for example thedynamic typed language PHP for the small web project Facebook?

Manuel Kiessling

Like Reply4 months ago in reply to Ronny Bubke 1 Like

Yes not usable maybe was a little bit to hard defined. I try toexplain it so: the bigger the project will be the higher are theefforts for managing the software cause you have no compiletime checks. This means you have to test 100% of theprogram code you write. Refactoring also is a huge problemcause you don't have static types. This means you replace allnames with same name but that's can be the wrongbehaviour.

Facebook has a huge amount of developers which will sufferunder this fact. To explain Facebooks choice of PHP issimple. It was not initially intended to be the "biggest" projectin the world. Also it seems to be Mark Zuckerbergs favoritelanguage at this time. It would be an interesting questionwhat Facebook would do if they had the same languagedecission again.

And what you maybe not know is that Facebook uses PHPjust for their frontend. Have a look at this article:http://www.makeuseof.com/tag/f...

Ronny Bubke

Like Reply4 months ago in reply to Manuel Kiessling

Great tutorial Manuel! I'm really looking forward to the next installment.typo "We we do here is" -> "What we do here is"

probablyrobots

Like Reply4 months ago 1 Like

Hi probablyrobots,

Manuel Kiessling

Page 91: The Node Begineer Book

thanks for the info. I fixed this with commithttps://github.com/ManuelKiess... and updated the site.

Like Reply4 months ago in reply to probablyrobots

Finally I have found clear and great tutorial on nodeJS. Waiting for more!Thanks.

NodeJS learner

Like Reply4 months ago 1 Like

I think you and I went through the same growing pains while learningevent drive JavaScript and node.js! It's almost like watching a time lapseof what I learned. And I love the conversational tone; following thecontent was actually enjoyable! Keep up the good work!

shiirish

Like Reply4 months ago 1 Like

I would love to learn from your experience, anything you wouldapproach differently?

Manuel Kiessling

Like Reply4 months ago in reply to shiirish

Very well written and easy to follow. Really like your writing style. Manythanks!

Joel Van Horn

Like Reply4 months ago 3 Likes

Thanks for this! It's a solid start. I'll be following along.

Stephen Bush

Like Reply4 months ago 1 Like

dtuite

Page 92: The Node Begineer Book

Really nice tutorial. Looking forward to the rest of it! Thanks.

Like Reply4 months ago 1 Like

I'm no REST expert by any means, but I think your interpretation of RESTmight be a little off. I don't think 'start' and 'upload' would be interpretedas resources. The thing you upload would more likely be a resource, inthis case 'images'.

Also, I believe it's the router's job to take a path, and then route to theresource, rather than taking a resource to begin with. So the routemethod should be route(path), rather than route(resource). It kindafollows from my first point, because the router might not always berouting to a resource, since not everything is a resource. I know the resultis the same, but it would be more semantically accurate.

Jamie Murai

Like Reply4 months ago 1 Like

Hi Jamie,

I'm not happy with the part talking about REST, and I'm going tomodify it.

Regarding the route(path) stuff, you are right, and I changed itaccordingly, I hope you like it.

Manuel Kiessling

Like Reply4 months ago in reply to Jamie Murai

In "Finding a place for our server module", you define a global functionfirst then export it. What you really should do is assign an anonymousfunction to it. Remember that closures can be used anywhere, not just asfunction parameters.

Hello71

Like Reply4 months ago

Hello71

Page 93: The Node Begineer Book

Typo: "Requested received." -> ""Request received."

Like Reply4 months ago

Thanks for hinting at this. I fixed it with commithttps://github.com/ManuelKiess... and updated the page.

Manuel Kiessling

Like Reply4 months ago in reply to Hello71

Always wanted to get started with Node, but didn't have enough time forit ! So glad that you came up with this post, will definitely check back asyou add more !

Loads of Thanks !

suvash

Like Reply4 months ago 1 Like

This guidance is awesome. I am very impressed by the approachabilityand ease with which it can be read and digested.

Jimmy Miller

Like Reply4 months ago 1 Like

This is awesome! I've been sifting through so many articles and blogsabout node that have assumed waay too much for what I'm currentlycapable of. It's nice to see someone assume zero prior knowledge ofnode.

Also, do you think you will be working with Express? If you plan on doingso, I'm glad you started with barebones node, because for me at least itwas a lot easier to understand Express after working with node.

Thanks for the article! Looking forward to more.

Zachary Hodge

Like Reply4 months ago

Page 94: The Node Begineer Book

That's exactly what I thought, keeping it barebone node at least inthe beginning, in order to allow beginners to make the first stepbefore the second.

Maybe I'll expand it and add later chapters which explain how todo it in Express.

Manuel Kiessling

Like Reply4 months ago in reply to Zachary Hodge

Haha, cool. Either way, thanks for the resource!

Zachary Hodge

Like Reply4 months ago in reply to Manuel Kiessling 1 Like

awesome and helpful! cheers for this resource

Andy Jarrett

Like Reply4 months ago 1 Like

Hi Andy,

great to hear you like it. If you think there is anything that could beimproved, just let me know!

Manuel Kiessling

Like Reply4 months ago in reply to Andy Jarrett

Very nice and clear. Thank you! :)

Madeleine Alomar

Like Reply4 months ago 1 Like

Page 95: The Node Begineer Book

Hi Madeleine,

glad to hear you think it's clear. I'm afraid it maybe still is a bit toochatty here and there, so if you have ideas for improvements, justlet me know!

Manuel Kiessling

Like Reply4 months ago in reply to Madeleine Alomar

Wonderful piece - lays out everything from the ground up. Great job!

Yuval Adam

Like Reply4 months ago 1 Like

Hi Yuval,

good to hear that - this "everything from the ground up" approachis really important for me. Did you have to "leave" the site in orderto search for information that was missing here (except for theexternal links of course)?

Manuel Kiessling

Like Reply4 months ago in reply to Yuval Adam

its wonderful! thank you

Pharmapharma144

Like Reply4 months ago 1 Like

Thank you very much for spending the time to put this together, I willdefinitely check back soon!

Ben

Like Reply4 months ago 2 Likes

Hi Ben,

Manuel Kiessling

Page 96: The Node Begineer Book

thanks for your friendly comment. I'm trying to update thedocument at least once per day.

Like Reply4 months ago in reply to Ben

Nice article! Keep it coming.

timonv

Like Reply4 months ago 1 Like

this is really good. I'll be back for more definitely

jimisir

Like Reply4 months ago 1 Like

Thank you for doing this. So far its already a great resource.

Sam Bolgert

Like Reply4 months ago 1 Like

Hi Sam, glad to hear you like it!

Manuel Kiessling

Like Reply4 months ago in reply to Sam Bolgert

Thank you so much for this. I'm really grateful to you for all the pains youtook for writing this.

Prakhar

Like Reply4 months ago 1 Like

No pain at all - really loving it, especially when receiving such nicefeedback like yours! Thank you so much!

Manuel Kiessling

Like Reply4 months ago in reply to Prakhar

Page 97: The Node Begineer Book

This is one of the few beginner articles I made it all the way throughbecause of how well it's written.

These concepts are hardly new to me but you've laid it out in a way thatshowing other people what node.js is all about will be easy.

Paul Gibler

Like Reply4 months ago 12 Likes

Same for me! Can't wait for the next parts...

maxjaderberg

Like Reply4 months ago in reply to Paul Gibler

Hi Paul,

can't express how much your comment made my day! I hope thefull work will keep up to that.

Manuel Kiessling

Like Reply4 months ago in reply to Paul Gibler 5 Likes

Great tone and thorough explanations. It's a solid tutorial. I think it'll beimportant to expand the tutorial to show AJAX interactions with the clientside along with some server-side DB access.

Tyler Jewell

Like Reply4 months ago 3 Likes

Hi Tyler,

thanks for the suggestions. It's hard to decide what to include andwhat to not include in order to give beginners a focusedexperience, but on the other hand, it makes a lot of sense to simplybuild on the basic tutorial and introduce other concepts like thoseyou mentioned on top.

Manuel Kiessling

Page 98: The Node Begineer Book

Like Reply4 months ago in reply to Tyler Jewell

Thank you so much for this. Please get this done as soon as possible!

Herman

Like Reply4 months ago 2 Likes

Hi Herman,

thanks for this. I promise I'll do my best!

Manuel Kiessling

Like Reply4 months ago in reply to Herman 1 Like

please please get this done. Its great. I'd like to show this to people whoare asking what node.js is good for. Thanks for this great work.

theMaSch

Like Reply4 months ago 5 Likes

Hi theMaSch,

thanks so much for taking the time to read and commenting theway you did. Writing NodeBeginner already was a lot of fun, but Ithink now I actually start loving the work!

Manuel Kiessling

Like Reply4 months ago in reply to theMaSch

you need to replace sys.puts with console.log, sys.puts might go awaysome day, it's technically a legacy API.

also, i don't know if this complicates your tutorial too much or not, but if amodule only exposes one object you can just replace exports with thatobject so that the return value of require is just that object.

mikealrogers

Page 99: The Node Begineer Book

var start = function (val) {...}module.exports = start

////

require('test')('asdfa')

Like Reply4 months ago 4 Likes

Hi Mikeal,

thanks for the input, that's a really important point! I changed theusage of sys.puts to console.log throughout the whole documentwith commit https://github.com/ManuelKiess...

The page already reflects this change.

Regarding one-function-modules: I will definitely incorporate that!

Manuel Kiessling

Like Reply4 months ago in reply to mikealrogers

"Thus, node.js is really two things: a runtime environment and a library."

Well, actually, node is the library, but V8 (that fast JS VM made byGoogle) is the VM that the code runs inside.

But it's really a good tutorial!

Jann Horn

Like Reply4 months ago 3 Likes

Hi Jann,

thanks for pointing this out. I rewrote that part to make thingsclearer (see commit https://github.com/ManuelKiess... ).

Manuel Kiessling

Page 100: The Node Begineer Book

The page already reflects this change - do you think it makes moresense now?

Like Reply4 months ago in reply to Jann Horn 1 Like

@Manuel,I just wanted to thank you millions dude, it's super clear andto the point tutorial. Simply put, an amazing manual.

SOMEONE PLEASE HELP:I'm a complete newbie to node.js and quite excited to try outthe tutorial as I keep reading but unfortunately the codesdon't seem to run; could you spare a second and perhapssee what I'm doing wrong:

I downloaded the complete Windows based package from: http://node-js.prcn.co.cchttp://node-js.prcn.co.cc/bin/...

- extracted the folders- renamed folder: node-0.4.7-i686-pc-cygwin-complete to node-js- placed the folder in c: so my node-js folder is at: c:\node-js- run the node.exe file at: c:\node-js\bin\node.exe- opened notepad, saved the code for helloworld with thefilename helloworld.js- placed the helloworld.js at c:\node-js\bin so the file isat c:\node-js\bin\helloworld.js- in the command line window open (the node.exe window)typed either of the following:> node helloworld.jsOR> node c:\node-js\bin\helloworld.jsbut in both cases I only get (...) and nothing happens and nooutput from system happens.

I have no idea what i'm doing wrong, I love to continue with

ama

Page 101: The Node Begineer Book

M Subscribe by email S RSS

Reactions

Show more reactions

Trackback URL http://disqus.com/forums/nodebeginner/the_node_beginner_book/trackback/

The Node Beginner Book by Manuel Kiessling is licensed under a

learning but this is stopping me from going further because Ican't run any of the codes in the tutorial,

any guidance would be so much appreciated,cheers,am.

Like Reply2 months ago in reply to Manuel Kiessling

Try node helloworld.js from a cmd.exe window.e.g. c:\node-js\bin> node helloworld.js

Adam Gruer

Like Reply2 months ago in reply to ama

Yes, thank you.

Jann Horn

Like Reply4 months ago in reply to Manuel Kiessling

Page 102: The Node Begineer Book

Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. Permissions beyond the scope of this license may be available at [email protected].