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 beforeresponse.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.
- 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.
Top comments (4)
Nice but I think It would better that you introduce the core node.js and how it works internally because it is interesting and important (Event Loop & Worker Pool)
Yep, these topics are important too. But I wrote this post to just give basic overview of Node and Express. Actually, title of this post should be - Basic Server Side applications with Node and Express !
Superb article Jaskaran!! Got clear idea about Node js and Express js.
Thanks...
Good one !
Some comments have been hidden by the post's author - find out more