HTTP Server from Scratch
While frameworks like Express or Fastify are popular, learning how to build a web server using the native http module is essential for understanding server-side Web engineering.
1. Creating a Basic HTTP Server
Node.js provides the native http module. The createServer() method takes a callback function with request (req) and response (res) arguments:
import http from "http";
const server = http.createServer((req, res) => {
// Set headers and response body
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World from Node.js Native Server\n");
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
});2. Inspecting the Request Object
The req parameter is an instance of http.IncomingMessage. It is a readable stream, allowing you to extract:
- req.url: The path of the request (e.g.,
/api/users?id=5). - req.method: The HTTP verb (e.g.,
GET,POST,PUT,DELETE). - req.headers: A dictionary containing all header keys and values.
import http from "http";
const server = http.createServer((req, res) => {
console.log(`HTTP Method: ${req.method}`);
console.log(`Request URL: ${req.url}`);
console.log(`User-Agent: ${req.headers["user-agent"]}`);
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "ok", path: req.url }));
});
server.listen(3000);3. Parsing Request Bodies (POST/PUT data)
Because request data is streamed, we must collect incoming buffers chunk by chunk, concatenate them, and parse the payload when the transmission completes:
import http from "http";
const server = http.createServer((req, res) => {
if (req.method === "POST" && req.url === "/api/login") {
let body = "";
// Accumulate stream chunks
req.on("data", (chunk) => {
body += chunk.toString();
});
// Parse when stream ends
req.on("end", () => {
try {
const payload = JSON.parse(body);
console.log("Login payload:", payload);
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: true, message: `Welcome, ${payload.username}` }));
} catch (err) {
res.writeHead(400, { "Content-Type": "text/plain" });
res.end("Invalid JSON format");
}
});
} else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Endpoint not found");
}
});
server.listen(3000);4. Sending Structured HTTP Responses
The res parameter is an instance of http.ServerResponse, which inherits from WritableStream.
- res.writeHead(statusCode, headers): Writes status code and response headers.
- res.setHeader(name, value): Sets or updates a single response header.
- res.write(chunk): Appends content data to the outgoing body stream.
- res.end(chunk): Flushes all remaining response data and terminates connection.
Published on Last updated: