'N' and 'E' of MERN - Basics of Node.js and Express.js

Introduction

What is Node.js?

Node.js is an open-source, cross-platform, back-end, JavaScript runtime environment that executes JavaScript code outside a web browser.

Open source - because it’s source code is available for use and modification legally.
Cross platform - works across different platforms like Linux, OSX and Windows.
Backend - receives requests from clients and contains the logic to respond to it.
JS runtime environment - where JavaScript code gets parsed and executed.

Node is a JavaScript environment built on the same JavaScript engine used in Google’s Chrome web browser. It has some great features that make it an attractive choice for building server-side applications, including web servers and web services for platform APIs.

Primary goals of this article -

  • Understand how Node.js applications are built
  • Implement a TODO application using Node.js
  • Implement REST APIs using Express.js

Prerequisite - As Node.js is based on JavaScript, it’s easier to learn to get started with for developers who know JavaScript. This also means that both the frontend and backend can now be written with just JavaScript knowledge.

Before we jump in, make sure you have node installed.
Install from Here.

Let's get started-
Let’s look at how to create a simple server using Node.js

create a file app.js and paste the following code-

// File: app.js

const http = require('http');
const port = 8081;

http.createServer((request, response) => {

    // Set response status code and response headers
    response.writeHead(200, { 'Content-Type': 'text/html' });

    // Set response body i.e, data to be sent
    response.write('<h1>TODO</h1>');

    // Tell the server the response is complete and to close the connection
    response.end();

}).listen(port, () => {

    // Log text to the terminal once the server starts
    console.log(`Nodejs server started on port ${port}`)

});

Execute node app.js in the terminal. You will see the following in terminal-

Nodejs server started on port 8081

Basically your server has started on port 8081 !!
Let's test it with curl:

curl -X GET http://localhost:8081

Or visit http://localhost:8081 in your browser to see the response sent by the above server.
That’s it! You’ve just built your first Node app.

So, What's happening with above code?
http is an inbuilt Node module, you can use require() to import it.
The http module exposes a function createServer() which can be used to create an HTTP server.
You have to pass a callback function as a parameter to the createServer() function. This function gets executed every time the server receives a request. The parameters to the callback function are the HTTP request and response objects.
We used these response object methods -

  • writeHead() - the first parameter is the response status code and the second any response headers.
  • write() - to add response body to be sent back to the client.
  • end() - tells the server that the response is complete. and OfCourse, we can add any number of response.write() calls before response.end() is called to send more data.

Here, We are just sending a h1 tag with text as 'TODO'.
curl command prints out the response as such-

<h1>TODO<h1>

The browser renders the HTML tag and displays an h1 heading with text, TODO.
TODO browser render

  • The listen() method sets the port in which the server listens to the requests. You can also add a callback function to listen() which will get executed once, when the server starts. Normally, we add lines such as Nodejs server started on port 8081 to make sure that server is listening.

Routing

Ok. So currently our server sends same response (h1 Tag) with status code 200 to every( irrespective of url and method) request it receives.
Let's change the body of createServer() method with following-

const { method, url } = request;
//fetch request method and path by using the request object’s method and url properties.

if (url == "/todos") {

    if (method == "GET") {
        response.writeHead(200, { 'Content-Type': 'text/html' });
        response.write('<h1>TODO</h1>');
        response.write('<p>Track your work</p>');
    } else {
        response.writeHead(501); //or response.statusCode = 501
    }

} else {
    response.writeHead(404);
}

response.end();

Now the server checks if url variable is /todos ?
If so, check if method is GET ?
If so, return the header and HTML response
Else, return just a 501 status code
Else, return 404 status code.

Now if you try to

curl -X GET http://localhost:8081/random

Can you guess what response are you going to get from server?
The url path is /random, so server sends response with status code as 404.
if you try to

curl -X POST http://localhost:8081/todos

yes, the url is /todos, but the method is POST, now you will get response code as 501.

Note that - 200 OK response status code is send by default if it’s not set explicitly.

Request Body

The request object that's passed in to a handler implements the ReadableStream interface. This stream can be listened to or piped elsewhere just like any other stream. We can grab the data right out of the stream by listening to the stream's 'data' and 'end' events.
The request.on() method can be used to look for the stream events. The data is read in chunks and is a buffer.
Once the whole data is read (known by the end event), you can parse the JSON data as a JavaScript object using the JSON.parse() function.

let body = '';

    request.on('error', (err) => {
        console.error(err);

    }).on('data', (chunk) => {

        body += chunk;  //keep concatenating the chunk 

    }).on('end', () => {
        body = JSON.parse(body);
    });

URL Module

What if we want to filter the response based on url parmaters??
We can use the Built-in URL Module-
The URL module splits up a web address into readable parts.

var url = require('url');
var adr = 'http://localhost:8081/default.htm?year=2017&month=february';  //request.url
var q = url.parse(adr, true);

console.log(q.host); //returns 'localhost:8081'
console.log(q.pathname); //returns '/default.htm'
console.log(q.search); //returns '?year=2017&month=february'

var qdata = q.query; //returns an object: { year: 2017, month: 'february' }
console.log(qdata.month); //returns 'february'

Now, If you have gone through the complete article up to this point, you have really good knowledge of Node.js and of course, there are always so many new things to explore.

Express

Express.js is a Node.js framework and makes it easier to build APIs.
We will be implementing the same APIs we created using Node.js. You can then compare both the implementations to view how Express.js makes it easier.
First, let’s get Express to work on your system.

$ npm install express

Express enables you to create a web server that is more readable, flexible, and maintainable as compared to developing a web server using only the Node HTTP library, which can get complicated for even the most basic web servers.

Routing in Express and HTTP Methods

The syntax for defining a route handler function is:

app.httpMethod(path, handler) {...}

Here, httpMethod can be get, put, post, delete, etc. The path is the actual route where the request will go and the handler is the same callback function which were passing to createServer() in node.js that is it will execute when the requested route is found.
Let's implement the GET API to the /todos path using Express

const app = express();

app.get("/todos", (request,response) => {
    response.status(200);
    response.send('<h1>TODO</h1>');

});
const port = 8081;

app.listen(port, function(){

    console.log(`Nodejs server started on port ${port}`)

});
  • Express Server is initialized using the express() method.
  • For GET, we used app.get() method, likewise you will use app.post(), app.delete() etc. for other HTTP methods.
  • The response object’s send() method is used to send the response body.
  • To bind the server to a port, you use the listen() method on the Express application, app.

As Javascript is a case-sensitive language, app.GET() won’t work.

Express Middlewares

Middleware functions are those that have access to request and response objects just like we do within routes. Middlewares are capable of changing requests, response objects, and can end the response cycle as well. You can think of middleware as a stack of functions that gets executes whenever a request is made to the server.
Generally, a middleware function takes 3 parameters: a request object, a response object, and a "next" function. Whenever you write a middleware, you must call this next() function at the end of every middleware function you write. In order to use middleware in your application, you have to make a call to app.use() and pass a middleware function as an argument.
For example-

// User defined Middleware
app.use(function(req, res, next){
   console.log('Inside Middleware function...');
   next();
});

If you do not call next(), no more route handlers or middleware will be processed. If still for some reason, you don't want to call next() then just send a response to the client, or else the client will remain in hang state and eventually get timed out.

Now we have basic understanding of Express, let's complete our TODO application using Express.

const express = require('express'); 
//importing express

const app = express();
//initializing express app

app.use(express.json())
//express.json() middleware to parse the request body as JSON.

const port = 8081

let todoList = ["Complete writing blog", "Complete project"];

/* Get all TODOS:   
** curl -v http://localhost:8081/todos
*/
app.get("/todos", (request, response) => {
    response.send(todoList);
});

/* Add a TODO to the list
** curl -v -X POST -d '{"name":"Plan for next week"}' http://localhost:8081/todos -H 'content-type:application/json'
*/
app.post("/todos", (request, response) => {
    let newTodo = request.body.name;
    todoList.push(newTodo);
    response.status(201).send();
});

/* Delete a TODO to the list
** curl -v -X DELETE -d '{"name":"Complete writing blog"}' http://localhost:8081/todos
*/
app.delete("/todos", (request, response) => {
    let deleteTodo = request.body.name;
    console.log(deleteTodo);
    for (let i = 0; i < todoList.length; i++) {
        if (todoList[i] === deleteTodo) {
            todoList.splice(i, 1);
            response.status(204).send();
        }
    }
});

app.all("/todos", (request, response) => {
    response.status(501).send()
})

app.all("*", (request, response) => {
    response.status(404).send()
})

app.listen(port, () => {
    console.log(`Nodejs server started on port ${port}`)
});

What is app.all()?
To send a 501 status code for requests to /todos other than GET, POST and DELETE, we can use the app.all() method below the current set of routes.
Express returns a 404 status code with HTML content by default for any unimplemented route or we can also use the app.all() method at the end to add a custom 404 handler.

Conclusion

Congratulations on making till the end. We have learned a lot in this article, I hope you now have a decent knowledge of Node and Express. Now you can create simple applications using the Node.js framework, Use Node.js to create a web server that listens to multiple routes, Utilize the Express.js library in your Node applications. I will come with more articles on this topic soon.

Till then: Keep Learning :)

Also, please ❤️, if you liked this article.

14