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.
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 thehttp
module. This is a core module that ships with the Node.js installation. - Next, you call the imported
createServer()
function to get aserver
object. You store the object in a constant namedserver
. - The
server
object has a method namedlisten()
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:
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:
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:
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?
Various Phases of the Node.js Event Loop
You can also connect with me on other platforms:
Top comments (0)