
There are actually two parts to writing a simple Node.js application. First, we need to import the HTTP module provided by Node.js. Once the module is imported using either the common js’ require method or ECMAScript import, we need to initiate the server using the createServer method which registers a callback function with arguments, requests, and responses.
All the code that’s executing in the Node.js environment is an async task. The very callback function the createServer method just registered with the event loop will be triggered every time a new request hits the server and the request and the response objects are all prepared by either the thread pool or the async interface of the OS kernel.
What follows the callback is pretty straightforward. We take the request object (req), pull out the details required, if available and then push a response back to the originator of the request (the client) in reply to its demand(s) using res object. Simple isn’t it? Maybe, or let’s first see what these two callback objects are and then try to make sense out of them.
Understanding The Request Object
Request, as the name suggests, is the handler for all the requests that hit the server. It’s a plain JavaScript object with all the nitty-gritty details about the request in the target, more specifically the IP address of the client requesting, the hostname, headers, body (JSON or otherwise), params, query strings and more related information that make a request legitimate in all the server environments.
Reading The Params In The Request URL
const params = req.params
It’s a server’s responsibility to parse the request properly and appropriately respond to it. While Node.js does the parsing of the request, it’s a programmer’s job to read the request object and respond to it to complete the request-response transaction.
And The Response Object
In order for a transaction to complete, a valid response must be sent back to the client. But what’s valid and what’s not? How to send a response back and what?
Node.js provides a minimal response API for eliminating such situations. The response object we receive as a callback for a request holds all the necessary methods for replying back to the client, be it a set header for setting response headers, or append for attaching data to the response body, or even the end method for finally ending the response process.
res.setHeader(‘Content-Type’, ‘text/plain’)
While the use of predefined methods doesn’t mean the response sent has to be valid, it certainly makes sure the error rate is kept to a minimum.
Why Do We Listen, At All?
The final piece of the puzzle is the listening method. What is it and why do we need it at all after initializing a server instance?
Well, if you took Networking classes, you might already know that while clients are arbitrary, a server is a single system whose address is known to every client that wants to connect to it. Now, in order to be present to all of them, a server implements a listen and accept architecture. Once a request is made, it’s put in a queue and pulled out once the server is ready to accept it.
Here, listen method does the listening part in the Node.js architecture while the createServercallback can be treated as accepted.
Listen takes in four parameters. First is the port number on which the Node.js process must run, with the second being the hostname that along with the port create a unique process identifier for the server.
const PORT = 8080,
HOSTNAME = ‘127.0.0.1’,
BACKLOG = 10
server.listen(PORT, HOSTNAME, BACKLOG, () => {
console.log(‘Server is now listening on’, PORT)
})
The third and the fourth parameters of the method are default backlog for pending listener queue and callback for the successful beginning of listener, respectively.
While all the parameters listen accepts are optional, it is always better to assign values for port and hostname and if required, for backlog too. The reason for doing so is the default values. If the OS finds no custom port or it is set to 0, it assigns an arbitrary unused port to the process. The same goes with hostname. If the server finds no custom value for it, it starts accepting connections on the unspecified IPv4 address (0.0.0.0) or the unspecified IPv6 address (::), if available. Both of the default values are unacceptable in a production environment, whether running behind a proxy server or directly on HTTP (Port 80).
With this simple code setup we can easily start a very minimal server that returns a plain text — “Hello, this is a sample server!” — on every kind of request. Put together the pieces of code above in a js file (server.js) and run the node process like this,
You will see that the script returns a log message — “Server is now listening on 8080” — as we defined in the listener callback. The best part of all is that Node.js will keep running and won’t even eat up any CPU resources for listening, it will simply sleep unless of course there’s a new request to be handled.
With that, we sum up this introduction to Node.js. We got to know what Node.js is, what caused an urgency for a single threaded server architecture like Node.js, what an event loop is, and how to start a simple HTTP server. We also got to know what the request and response objects are and how Node.js listens and accepts new requests and processes them to complete the request-response transaction with the help of an event loop.

Alex Mercer, a seasoned Node.js developer, brings a rich blend of technical expertise to the world of server-side JavaScript. With a passion for coding, Alex’s articles are a treasure trove for Node.js developers. Alex is dedicated to empowering developers with knowledge in the ever-evolving landscape of Node.js.





