The use cases
Let's keep it easy, however realistic:
➤ The user ought to be able to use our application with an online browser
➤ The user ought to see a welcome page once requesting http://domain/start that displays a file transfer kind
➤ By selecting a picture file to transfer and submitting the shape, this image ought to then be uploaded to http://domain/upload, wherever it's displayed once the transfer is finished
Fair enough. Now, you'll reach this goal by googling and hacking along one thing. however, that is not what we would like to try to here.
Furthermore, we do not wish to put in writing solely the foremost basic code to attain the goal, but elegant and proper this code may be. we'll designedly add a lot of abstraction than necessary so as to urge a sense for building a lot of advanced Node.js applications.
The application stack
Let's dissect our application. those elements got to be enforced so as to satisfy the utilization cases?
➤ We want to serve websites, so we'd like an associate HTTP server
➤ Our server can be got to answer otherwise to requests, betting on that URL the request was inquiring for, so we'd like some reasonable router so as to map requests to request handlers
➤ To fulfill the requests that came across the server and are routed using the router, we'd like actual request handlers
➤ The router most likely ought to additionally treat any incoming POST information and provides it to the request handlers in a very convenient type, so we'd like request information handling
➤ We not only need to handle requests for URLs, we have a tendency to additionally need to show content once these URLs square measure requested, which suggests we'd like some reasonably read logic the request handlers will use so as to send content to the user's browser
➤ Last however not least, the user are able to transfer pictures, therefore we have a tendency to square measure getting to want some reasonably transfer handling that takes care of the main points
Let's suppose a flash concerning however we'd build this stack with PHP. it isn't specifically a secret that the everyday setup would be associate Apache HTTP server with mod_php put in.
This successively implies that the total "we got to be able to serve websites and receive HTTP requests" stuff does not happen inside PHP itself.
Well, with node, things square measure a touch completely different. as a result of Node.js, we have a tendency to not solely implement our application, we have a tendency to conjointly implement the total HTTP server. In fact, our net application and its net server square measure essentially identical.
This may sound sort of a heap of labor, however, we are going to see in a very moment that with Node.js, it's not.
Let's simply begin at the start and implement the primary a part of our stack, the HTTP server.
Building the application stack
A basic HTTP server
When I got hold of the purpose wherever I wished to begin with my initial "real" Node.js application, I wondered not only the way to truly code it, however additionally the way to organize my code.
Would I like to own everything in one file? Most tutorials on the net that teach you ways to write a basic HTTP server in Node.js have all the logic in one place. What if I need to create positive that my code stays readable the additional stuff I implement?
Turns out, it's relatively simple to stay the various considerations of your code separated, by swinging them in modules.
This allows you to own a clean computer file, that you execute with Node.js and clean modules which will be employed by the most file and among one another.
So, let's create the main file that we have a tendency to use to begin our application, and a module file wherever our HTTP server code lives.
My impression is that it's additional or less a regular to call your main file index.js. It makes sense to put our server module into a file named server.js.
Let's begin with the server module. create the digital computer.js within the root directory of your project, and fill it with the subsequent 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 only wrote a working HTTP server. Let's prove it by running and testing it. First, execute your script with Node.js:
node server.js
Now, open your browser and point it at http://localhost:8888/. This should display a web page that says "Hello World".
That's quite interesting, isn't it? however about talking about what is going on here and leaving the question of the way to organize our project for later? I promise we'll go back to it.
Analyzing our HTTP server
Well, then, let's analyze what is truly occurring here.
The first line needs the http module that ships with Node.js and makes it accessible through the variable http.
We then call one in every of the functions the http module offers: createServer. This function returns an object, and this object has a method named listen, and takes a numeric price that indicates the port range our http server goes to listen on.
Please ignore for a second the perform definition that follows the opening bracket of http.createServer.
We could have written the code that starts our server and makes it listen at port 8888 like this:
var http = require("http");
var server = http.createServer();
server.listen(8888);
That would begin an http server listening at port 8888 and doing nothing else (not even answering any incoming requests).
The very interesting (and, if your background could be a a lot of conservative language like PHP, odd looking) part is that the function definition right there wherever you'd expect the first parameter of the createServer() call.
Turns out, this function definition is that the 1st (and only) parameter we are giving to the createServer() call. because in JavaScript, functions can be passed around like any alternative value.
Passing functions around
You can, for example, do something like this:
function say(word) {
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
Read this carefully! we pass the function say as the 1st parameter to the execute function. Not the return value of say, however, say itself!
Thus, say becomes the local variable someFunction within execute, and execute will call the function in this variable by provision someFunction() (adding brackets).
Of course, because say takes one parameter, execute will pass such a parameter when calling someFunction.
We can, as we simply did, pass a function as a parameter to a different function by its name. however we do not got to take this indirection of 1st defining, then passing it - we will define and pass a function as a parameter to a different function in-place:
function execute(someFunction, value) {
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
We define the function we wish to pass to execute right there at the place wherever execute expects its 1st parameter.
This way, we do not even need to provide the function a name, which is why this can be called an anonymous function.
This is a first glimpse at what i prefer to call "advanced" JavaScript, however let's take it step by step. For now, let's simply accept that in JavaScript, we can pass a function as a parameter when calling another function. we can try this by assigning our function to a variable, which we then pass, or by defining the function to pass in-place.
How function passing makes our HTTP server work
With this information, let's revisit 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 currently it ought to be clear what we are actually doing here: we pass the createServer function an anonymous function.
We might come through 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 could be an honest moment to ask: Why are we doing it that way?
Event-driven asynchronous callbacks
To understand why Node.js applications need to be written this manner, we want to understand however Node.js executes our code. Node's approach is not unique, however, the underlying execution model is different from runtime environments like Python, Ruby, PHP or Java.