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 listens for requests from other machines (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, you can imagine, it does it quite well 😉.
In many cases, we will use some type of framework or library to create an HTTP server with Node.js. However, we have the native HTTP module available that 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 accessed at 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:
- Making a
GET
request to/api/users
returns a list of users in JSON format. - Making a
POST
request to/api/users
expects a JSON body with the new user’s data. This simulated user would be added to a database (simulated here) and a success message along with the new user’s details would be returned. - 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 images 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
contentType
object that maps file extensions to MIME types to serve different types of files. - Reads the requested file from a
public
directory. - 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