Build your own Express.js - Part One
Tags: node, javascript, tutorial, serverless
Published: 2019-10-09 17:43:48

This is going to be a multipart series in which we are going to build a minimal, simple and yet powerful version of <a href="https://expressjs.com/" target="_blank">Express.js</a>, called <a href="https://github.com/yomeshgupta/minimaljs.git" target="_blank"><span class="u-text--highlight">**Minimal.js**</span></a>. We are going to talk about Node.js in-built modules, HTTP server, routing, middlewares and much more.

We all are learning on the go so if you find any mistake or any better way to do certain things or just want to share your feedback then I am all ears and open to collaboration. <a href="https://www.twitter.com/yomeshgupta" target="_blank">Let me know your opinions here</a>.

## Introduction

<a href="https://expressjs.com/" target="_blank">Express</a> has become the de-facto standard framework for web server applications in Node.js. It is easy to use, has a low learning curve, exceptionally well plug & play middleware system and it's minimal by design. As its homepage says,

> Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

In this series, we are going to build a similar (but quite simpler) web framework like Express. Our architectural decisions and API design will be as close to Express as possible. However, some implementations would be different so take it with a pinch of salt. :P

## Prerequisites

1. The latest stable version of Node.js installed
2. Basic understanding of JavaScript and Node.js runtime.

## Part 1

This part would be a very simple introduction to Node.js modules, HTTP and we are going to create a basic server from scratch. If you already know all this then you can skip this one and move to <a href="https://devtools.tech/build-your-own-express-js-part-two">part 2</a>.

I would recommend that you should code along. So, go ahead, clone the repo and checkout <span class="inline-code">`start`</span> branch

```bash
git clone https://github.com/yomeshgupta/minimaljs.git
git checkout start
```

### HTTP

This page is generated by a mix of HTML, CSS, and JavaScript, sent to you by Devtools via the internet. The Internet is full of pages like this and a lot of cat pictures. ALOT! 🐱 These pages are hosted on different servers all around the world. When we visit the internet and access any content, our browser must ask the servers for the content it wants and then display it to us. The content here is also known as a resource that can be of varied types such as HTML files, images, videos, scripts and many more. The protocol which governs all this communication is known as HTTP.

HTTP stands for <span class="u-text--highlight">**Hypertext Transfer Protocol (HTTP)**</span>. It is a protocol that is used to structure communication between client and server. A client makes a request to the server and the server provides apt response. It is a stateless protocol i.e. two requests to a server are mutually exclusive and the server does not keep any data between those requests.

The transfer of resources between server and client happens using <span class="u-text--highlight">**TCP (Transmission Control Protocol)**</span>. When you type an url such as <a href="https://www.devtools.tech" target="_blank">www.devtools.tech</a> into your browser then you are asking it to open a TCP channel to the server that resolves to that url. The server receives the request, processes it, sends back the response to the client (your browser) and closes the connection. When you again open the url then the entire procedure is followed again.

HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. They are commonly referred as HTTP verbs. I am listing some verbs below:

1. <span class="inline-code">GET</span> - Requests made to retrieve data.
2. <span class="inline-code">POST</span> - Requests made to submit data to server, resulting in change of state or side effects on server.
3. <span class="inline-code">PUT</span> - Requests made to replaces all current representations of the target resource with the request payload.
4. <span class="inline-code">DELETE</span> - Requests made to delete the specified resource on the server.

Complete list can be found <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods" target="_blank">here</a>.

Just like the requests method, we have response status codes that are important for interpreting the server's response on the client-side. Some of the status codes are

1. <span class="inline-code">200</span> - Successful
2. <span class="inline-code">404</span> - Not Found
3. <span class="inline-code">500</span> - Internal Server Error
4. <span class="inline-code">301</span> - Redirect

Complete list can be found <a href="https://httpstatuses.com/" target="_blank">here</a>.

To read more about HTTP, checkout this <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP" target="_blank">MDN resource page</a>.

### Let's build

Node.js provides a lot of powerful modules built-in; <a href="https://nodejs.org/docs/latest-v10.x/api/http.html" target="_blank">HTTP</a> is one of those modules. As docs put it,

> The HTTP interfaces in Node.js are designed to support many features of the protocol which have been traditionally difficult to use.

We are going to require <span class="inline-code">`http`</span> in our <span class="inline-code">`server.js`</span>

```js
const http = require('http');
```

It provides us a method <span class="inline-code">`createServer`</span> which takes a callback <span class="inline-code">`requestListener`</span> as an argument and returns a new instance of <span class="inline-code">http.Server</span>. Let's use this.

```js
const http = require('http');

const server = http.createServer((req, res) => {
	// request handling
});
```

Now, we a <span class="inline-code">http.Server</span> instance in <span class="inline-code">server</span> variable. Calling, <span class="inline-code">listen</span> method on it will allow our server to receive requests as in it will bind the server to a port and listen for incoming connections.

```js
...
const server = http.createServer((req, res) => {});

server.listen(8080, () => console.log("Server running on port 8080"));
```

By doing this much, our server is live! However, what to do when an actual request comes in?? How to handle that?

The <span class="inline-code">`requestListener`</span> we talked about earlier is the one which executes when a request comes in. It receives two parameters:

1. <span class="inline-code">`request`</span> object contains information about the current request such as URL, HTTP headers, and much more.
2. <span class="inline-code">`response`</span> object contains methods which are used to send data back to client.

```js
...
const server = http.createServer((req, res) => {
	res.writeHead(200, {"Content-Type": "text/html"});
	res.write("Hello world");
	res.end();
});
...
```

In above code snippet,

1. We are calling <span class="inline-code">response.writeHead()</span> which sends a HTTP status code and a collection of response headers back to client. Here, we are setting <span class="inline-code">statusCode 200</span> and <span class="inline-code">Content-Type: text/html</span>.
2. We are calling <span class="inline-code">response.write()</span> which is used to send data to the client.
3. By calling <span class="inline-code">response.end()</span>, we are informing the server that response headers and body have been sent and request has been fulfilled. Server closes the connection after this method call.

Let's refactor a bit and create a <span class="inline-code">`config.js`</span> file to store our app's configurations.

```bash
touch config.js
```

Add the following code to it and require it in our <span class="inline-code">server.js</span>

```js
module.exports = {
	PORT: 8080 // or any other port you wish to run your server on
};
```

The road so far...

```js
const http = require('http');
const { PORT } = require('./config');

const server = http.createServer((req, res) => {
	res.writeHead(200, { 'Content-Type': 'text/html' });
	res.write('Hello world');
	res.end();
});

server.listen(PORT, () => console.log(`Server running on ${PORT}`));
```

Our server works so far and we have implemented a catch-all route that serves the same <span class="u-text--highlight">**Hello World**</span> content for any URL you visit on the server. Let's make it a little nice and show some actual good old HTML. 😄

Create a <span class="inline-code">public</span> folder in your root directory and inside that folder make an <span class="inline-code">index.html</span>

```bash
mkdir public
cd ./public
touch index.html
```

Add the following html to index.html

```html
<!DOCTYPE html>
<html>
	<head>
		<title>Minimal.js | Part 1</title>
		<style>
			* {
				margin: 0px;
				padding: 0px;
				font-family: 'Roboto';
			}
			html,
			body {
				width: 100%;
				height: 100%;
			}
			body {
				background-color: #ececec;
				background-image: url('http://wallpaper.yomeshgupta.com/images/5.jpg');
				background-size: contain;
				background-position: center top;
			}
			h1 {
				max-width: 400px;
				margin: 0 auto;
				padding: 40px 0px;
				font-size: 18px;
				text-align: center;
			}
			a {
				color: #f67b45;
			}
			a:hover {
				color: #227093;
			}
		</style>
	</head>
	<body>
		<h1>
			Hello World. To see more wallpapers like this and make your new tab more delightful. Check out this
			<a href="https://chrome.google.com/webstore/detail/backdrops/beanogjmmfajlfkfmlchaoamcoelddjf"
				>Chrome Extension</a
			>.
		</h1>
	</body>
</html>
```

Now, let's require two Node.js in-built modules, <span class="inline-code">fs</span> and <span class="inline-code">path</span>

```js
const fs = require('fs');
const path = require('path');
```

<span class="inline-code">fs</span> module is the File System module which provides an API for interacting with the file system. Basically, if you want to read any file, write to any file, make a directory, change permissions or anything else file system related; <span class="inline-code">fs</span> is THE CHOSEN ONE.

<span class="inline-code">path</span> module is basically a collection of utilities which helps while working with file system. It provides capabilities like resolving a path, finding directory name, finding the extension of a given file/path and so much more!

Use these modules to read and serve our newly created index.html to incoming requests

```js
...
const fs = require('fs');
const path = require('path');

const server = http.createServer((req, res) => {
	fs.readFile(path.resolve(__dirname, 'public', 'index.html'), (err, data) => {
		res.setHeader('Content-Type', 'text/html');
		if (err) {
			res.writeHead(500);
			return res.end('Some error occured');
		}
		res.writeHead(200);
		return res.end(data);
	});
});
...
```

Here,

1. We are using <span class="inline-code">fs.readFile()</span> method to read the contents of our <span class="inline-code">index.html</span>. It takes two arguments, <span class="inline-code">file path</span> and <span class="inline-code">callback</span> which will be executed once the file is read.
2. In our callback, if we encounter any error then we are sending error response else we are serving index.html's content.
3. We are also using <span class="inline-code">path.resolve</span> to find the exact location of index.html on the disk.

You can read about these modules <a href="https://nodejs.org/docs/latest-v10.x/api/" target="_blank">here</a>.

Phew! Our first part is over. We, now, have our first without express HTTP server up and running! In part-2 we are going to take this up a notch and will start working on our framework. Stay tuned!

The complete code for this part can be found in this <a href="https://github.com/yomeshgupta/minimaljs/tree/part-1">Github repo</a>.

> Wallpaper used in the example here comes bundled with a super amazing minimal chrome extension, **Backdrops**. Check it out <a href="https://chrome.google.com/webstore/detail/backdrops/beanogjmmfajlfkfmlchaoamcoelddjf" target="_blank">here</a>.

Hopefully, this article helped you in some way and if yes, then kindly tweet about it by clicking <a href="https://twitter.com/intent/tweet/?text=Build your own expressjs -part one. devtools.tech/build-your-own-express-js-part-one @yomeshgupta&url=devtools.tech/build-your-own-express-js-part-one" target="_blank">here</a>. Feel free to share your feedback <a href="https://www.twitter.com/yomeshgupta" target="_blank">here</a>.