Node.js Webserver with HTTP Module is so easy!
No framework. No third-party modules.
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 find 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 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.
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 is needed to create a Node.js webserver.
We import
createServer()
function from thehttp
module. This is a core module that ships with the Node.js installation.Next, we call the
createServer()
function to get a server object. We store the object in a constant namedserver
.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, we can use the command node index.mjs
.
Of course, saying that this server is useless would be an understatement. 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 with Node.js Webserver
How do we make the server somewhat useful?
We give it the ability to handle requests. Check out the below code:
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 callback will handle every incoming request.
The response
object helps us manipulate the output. The writeHead()
method is used to set the response status code (200) and response headers. For example, we set the content-type
to text/plain
and charset
to utf-8
.
Next, we use response.write()
method to set the actual response string. You can have multiple response.write()
statements one after the other.
Once we are finished with the response, we need to tell the webserver to close the stream. This is done using response.end()
method. The response.end()
function 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?
HTML Response using Node.js Webserver
See the below code:
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()
function call.
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. Content depends on the request made by the user.
How can our Node.js webserver generate dynamic responses?
Dynamic Response with Node.js Webserver
The changes are pretty straightforward. See below:
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 we read the URL requested by the client using the request.url
property. For example, if the user enters the URL http://localhost:8080/?name=progressivecoder
in the address bar of the browser, the request.url
will contain the value /?name=progressivecoder
.
Since we want to display the name in the HTML response, we use the WHATWG URL API to create a URL instance. The URL API enables us to 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, we extract the query parameter name
from the URL object's searchParams
property.
If you access http://localhost:8080/?name=progressivecoder
after making the above change, you will see Hello progressivecoder
displayed in the browser window. This is a dynamic HTML output that depends on what we pass in the request's query parameters.
Concluding Thoughts
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 article or found it helpful, let's connect. Please hit the Subscribe button at the top of the page to get an email notification about my latest posts.
You can also connect with me on other platforms: