Node.js provides the HTTP module that allows us to create web servers easily without needing to rely on external libraries or frameworks.
An HTTP server is, basically, a program that is always on and constantly listening for requests from other computers (which we will call clients).
When a client requests a web page the HTTP server receives that request and processes it, returning the requested web page to the client.
HTTP servers are necessary for “the Internet to work”. Creating HTTP servers is one of the main purposes of Node.js. So, as you can imagine, it does it quite well 😉.
In many cases we will use some kind of framework or library to create an HTTP server with Node.js. However, we have the native HTTP module available which allows us to carry out most basic or intermediate projects.
Examples of using the HTTP module
Basic HTTP Server
This code creates a basic HTTP server that responds with “Hello World!” when accessed from a browser.
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World!\n');
});
// starts a simple http server locally on port 3000
server.listen(3000, '127.0.0.1', () => {
console.log('Listening on 127.0.0.1:3000');
});
HTTP Server with an HTML page
This example creates an HTTP server that serves a very (very) basic HTML page when accessed.
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>Simple Page</title>
</head>
<body>
<h1>Hello from Node.js!</h1>
</body>
</html>
`);
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
This code creates an HTTP server that returns an HTML page with a title and a header “Hello from Node.js!” when accessing http://127.0.0.1:3000/.
Basic REST API
This example shows how to create an HTTP server that handles different routes for a basic REST API.
import { createServer } from 'node:http';
const server = createServer((req, res) => {
const { method, url } = req;
if (method === 'GET' && url === '/api/users') {
// Simulating a user database
const users = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' },
];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(users));
} else if (method === 'POST' && url === '/api/users') {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
const newUser = JSON.parse(body);
// Here you could save the new user to the database
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'User added', user: newUser }));
});
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Route not found' }));
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
In this example:
- When making a
GETrequest to/api/users, a list of users in JSON format is returned. - When making a
POSTrequest to/api/users, a JSON body with the new user’s data is expected. This simulated user would be added to a database (simulated here) and a success message is returned along with the new user’s details. - Any other route will result in a “Route not found” message with a 404 status code.
Static File Server
This example shows how to serve static files, such as HTML, CSS, and image files from a specific directory.
import { createServer } from 'node:http';
import { readFile } from 'node:fs';
import { extname, join } from 'node:path';
const server = createServer((req, res) => {
let filePath = req.url === '/' ? '/index.html' : req.url;
const ext = extname(filePath);
const contentType = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript',
'.png': 'image/png',
'.jpg': 'image/jpeg',
}[ext] || 'application/octet-stream';
filePath = join(__dirname, 'public', filePath);
readFile(filePath, (err, content) => {
if (err) {
if (err.code === 'ENOENT') {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 Not Found</h1>');
} else {
res.writeHead(500, { 'Content-Type': 'text/html' });
res.end('<h1>500 Internal Server Error</h1>');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content);
}
});
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
This example:
- Defines a
contentTypeobject that maps file extensions to MIME types to serve different file types. - Reads the requested file from a
publicdirectory. - Handles errors such as file not found (404) or internal server errors (500).
- Serves the content of the requested file with the appropriate MIME type.
Download the code
All the code from this post is available for download on Github
