Building a Node.js Webserver with HTTP Module is super easy!
Tags: webdev, node, javascript, tutorial
Published: 2023-01-05 06:13:36

**What if your car breaks down on a highway and you have no clue what the mechanic is saying about the problem?**

This is the same as working with your Node.js webserver using frameworks such as Express. You know how to build applications. But you don't know how those applications work.

And that's usually fine until you have a need to leverage the platform more efficiently.

There are many easy ways to build a webserver by using frameworks such as Express. However, it is also **_not_** that hard to build a basic **Node.js Webserver** with the **core HTTP module** and nothing else. 

Even if you might not use it to build real applications, knowing how it's done has benefits if you want to become a real Node.js practitioner. Just like being an automobile enthusiast instead of a simple driver.

Surely, you don't want to be just a driver!

All right - so now that you are _hopefully_ convinced, let's build an extremely simple webserver in Node.js.

## Node.js Basic Webserver

Create a file named `index.mjs` in a project directory and paste the below code into the file.

```js
import { createServer } from "http";

const server = createServer();

server.listen(8080, () => {
    console.log(`Server is listening to http://localhost:${server.address().port}`);
});
```
And that's all the code that you need to create a Node.js webserver.

But what are you doing over here?

- First, you import `createServer()` function from the `http` module. This is a **core module** that ships with the Node.js installation.
- Next, you call the imported `createServer()` function to get a `server` object. You store the object in a constant named `server`.
- The `server` object has a method named `listen()` that takes a couple of arguments. One is the **port number** and the second is a **callback function** that prints a message when the server is ready to handle requests.

To start the server, you can execute the command `node index.mjs`.

Of course, you can say that this server is practically useless. And you won't be exaggerating.

When you visit `http://localhost:8080`, nothing happens. If you are lucky, you might get a timeout.

Even though the server is up and running, it does not know what to do with an incoming request.

## Handling HTTP requests

So, how can you make the Node.js webserver somewhat useful?

You need to give it the ability to handle requests. 

Check out the below code:

```js
import { createServer } from "http";

const server = createServer((request, response) => {
    response.writeHead(200, {'content-type': 'text/plain; charset=utf-8' })
    response.write('Hello');
    response.end(' World\n');
});

server.listen(8080, () => {
    console.log(`Server is listening to http://localhost:${server.address().port}`);
});
```

The `createServer()` function now takes a callback with two input objects - `request` and `response`. The job of this callback is to handle every incoming request.

The `response` object helps us manipulate the output. You can use the `writeHead()` method to set the **response status code** and **response headers**. For example, you can set the `content-type` to `text/plain` and `charset` to `utf-8`.

To set the actual response, you can use the `response.write()` method to set the response string. You can also have multiple `response.write()` statements one after the other.

Once the response is written, you need to tell the webserver to close the stream. This is done using the `response.end()` method. The `response.end()` method can also take some part of the response.

**But who uses a webserver to send some text response?**

Of course, there might be a requirement but it does **not** seem like the best use of a webserver.

**How about sending some HTML as a response?**

## Sending HTML Response

Check out the below code:

```js
import { createServer } from "http";

const server = createServer((request, response) => {
    response.writeHead(200, {'content-type': 'text/html; charset=utf-8' })

    const body = `<!DOCTYPE html>
        <html>
            <head>
                <meta charset="utf-8">
                <title>Node.js Webserver Demo</title>
            </head>
            <body>
                <h1 style="color: orange">Hello World</h1>
            </body>
        </html>`;

    response.end(body);
});

server.listen(8080, () => {
    console.log(`Server is listening to http://localhost:${server.address().port}`);
});
```

Despite the size of the code, there are only minor modifications.

One is setting the `content-type` value to `text/html`. The second is declaring a constant named `body` with some HTML content and sending it as part of `response.end()` method.

If you access `http://localhost:8080` now, you should see the HTML page displayed in the browser.

At this point, you might feel somewhat satisfied with the capabilities of the **Node.js webserver**. But the nature of the content is still pretty static.

Typical web applications consist of dynamic web pages. Output depends on the request made by the user.

**How can you make your Node.js webserver generate dynamic responses?**

## Sending Dynamic Response 
The changes are pretty straightforward. See below:

```js
import { createServer } from "http";

const server = createServer((request, response) => {
    response.writeHead(200, {'content-type': 'text/html; charset=utf-8' })

    const url = new URL(request.url, 'http://localhost:8080');

    const body = `<!DOCTYPE html>
        <html>
            <head>
                <meta charset="utf-8">
                <title>Node.js Webserver Demo</title>
            </head>
            <body>
                <h1 style="color: orange">Hello ${url.searchParams.get('name')}</h1>
            </body>
        </html>`;

    response.end(body);
});
server.listen(8080, () => {
    console.log(`Server is listening to http://localhost:${server.address().port}`);
});
```

The major change in the above snippet is that you are now reading the URL requested by the client using the `request.url` property. 

For example, if the user enters the URL `http://localhost:8080/?name=adamsmith` in the address bar of the browser, the `request.url` will contain the value `/?name=adamsmith`.

To display the name in the HTML response, I recommend using the **WHATWG URL API** to create a URL instance. The URL API helps you parse URLs and break them into individual components. It will produce an object that represents the requested URL with all of the components.

Within the HTML string, you can extract the query parameter `name` from the URL object's `searchParams` property using the expression `url.searchParams.get('name')`.

If you access `http://localhost:8080/?name=adamsmith` after making the above change, you will see **Hello adamsmith** displayed in the browser window. 

This is a **dynamic HTML output** that depends on what you pass in the request's query parameters.

--- 
There is no doubt using a framework makes life easy for developers. You ultimately write **less code** and focus more on business logic. Also, you write **less boilerplate code** to handle basic things when using a framework.

But knowing how things work under the hood of any framework is also important. Learning how to create a Node.js webserver with just the **core HTTP module** gives you important lessons on how the frameworks work internally.

If you enjoyed this post or found it helpful, do share it with friends and colleagues. Also, here are some other articles you might find useful:

[How does Node.js Reactor Pattern work?](https://progressivecoder.com/nodejs-reactor-pattern-event-loop/)

[Various Phases of the Node.js Event Loop](https://progressivecoder.com/a-deeper-look-at-nodejs-event-loop-phases/)

You can also connect with me on other platforms:

[My Regular Newsletter](https://progressivecoder.substack.com/)

[Twitter](https://twitter.com/ProgressiveCod2)

[LinkedIn](https://www.linkedin.com/in/saurabh-dashora-b3601173/)

[Youtube](https://www.youtube.com/channel/UCcD92x9BQLvvm-8jtsg12kw)