The http Module & Creating Servers
📖 Concept
The http module is Node.js's built-in module for creating HTTP servers and making HTTP requests. Every web framework (Express, Koa, Fastify) is built on top of it.
Creating a basic server:
const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello, World!');
});
server.listen(3000);
The request/response lifecycle:
- Client sends an HTTP request (method, URL, headers, body)
- Node.js's
http.Serveremits a'request'event - Your callback receives
req(IncomingMessage) andres(ServerResponse) - You read from
req(request data) and write tores(response data) - Call
res.end()to finish the response
req (IncomingMessage) — what the client sent:
req.method— GET, POST, PUT, DELETE, PATCHreq.url— The request URL path (/users?page=2)req.headers— Request headers (lowercase keys)reqis a Readable stream — body data arrives in chunks
res (ServerResponse) — what you send back:
res.statusCode = 200— Set HTTP status coderes.setHeader(name, value)— Set response headersres.writeHead(statusCode, headers)— Set status + headers at onceres.write(data)— Send response body (can call multiple times)res.end(data)— End the response (required!)
HTTP status codes to know:
| Code | Meaning | When to use |
|---|---|---|
| 200 | OK | Successful GET, PUT |
| 201 | Created | Successful POST (resource created) |
| 204 | No Content | Successful DELETE |
| 301 | Moved Permanently | URL changed permanently |
| 400 | Bad Request | Invalid client request |
| 401 | Unauthorized | Not authenticated |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 500 | Internal Server Error | Server-side bug |
🏠 Real-world analogy: An HTTP server is like a restaurant. The customer (client) sends an order (request) to the kitchen (server). The kitchen reads the order (req), prepares the food (processing), and delivers the plate (res). res.end() is putting the plate on the table — the order is complete.
💻 Code Example
1// HTTP Server — Built from scratch23const http = require("http");4const url = require("url");56// 1. Basic HTTP server7const server = http.createServer((req, res) => {8 // Parse URL and query parameters9 const parsedUrl = new URL(req.url, `http://${req.headers.host}`);10 const pathname = parsedUrl.pathname;11 const query = Object.fromEntries(parsedUrl.searchParams);1213 // Log request14 console.log(`[${req.method}] ${pathname}`, query);1516 // Set CORS headers17 res.setHeader("Access-Control-Allow-Origin", "*");18 res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");19 res.setHeader("Access-Control-Allow-Headers", "Content-Type");2021 // Handle preflight22 if (req.method === "OPTIONS") {23 res.writeHead(204);24 res.end();25 return;26 }2728 // Simple router29 if (pathname === "/" && req.method === "GET") {30 res.writeHead(200, { "Content-Type": "application/json" });31 res.end(JSON.stringify({ message: "Welcome to the API", version: "1.0" }));32 } else if (pathname === "/health" && req.method === "GET") {33 res.writeHead(200, { "Content-Type": "application/json" });34 res.end(JSON.stringify({ status: "healthy", uptime: process.uptime() }));35 } else if (pathname === "/users" && req.method === "GET") {36 const users = [37 { id: 1, name: "Alice" },38 { id: 2, name: "Bob" },39 ];40 // Support pagination via query params41 const page = parseInt(query.page) || 1;42 const limit = parseInt(query.limit) || 10;43 res.writeHead(200, { "Content-Type": "application/json" });44 res.end(JSON.stringify({ data: users, page, limit }));45 } else if (pathname === "/users" && req.method === "POST") {46 // Read request body (it's a stream!)47 let body = "";48 req.on("data", (chunk) => {49 body += chunk;50 // Prevent large payloads (DoS protection)51 if (body.length > 1e6) {52 res.writeHead(413, { "Content-Type": "application/json" });53 res.end(JSON.stringify({ error: "Payload too large" }));54 req.destroy();55 }56 });57 req.on("end", () => {58 try {59 const user = JSON.parse(body);60 // Validate61 if (!user.name) {62 res.writeHead(400, { "Content-Type": "application/json" });63 res.end(JSON.stringify({ error: "Name is required" }));64 return;65 }66 // Create user (mock)67 const newUser = { id: Date.now(), ...user };68 res.writeHead(201, { "Content-Type": "application/json" });69 res.end(JSON.stringify(newUser));70 } catch (err) {71 res.writeHead(400, { "Content-Type": "application/json" });72 res.end(JSON.stringify({ error: "Invalid JSON" }));73 }74 });75 } else {76 // 404 Not Found77 res.writeHead(404, { "Content-Type": "application/json" });78 res.end(JSON.stringify({ error: "Not found" }));79 }80});8182// 2. Error handling83server.on("error", (err) => {84 if (err.code === "EADDRINUSE") {85 console.error(`Port ${err.port} is already in use`);86 } else {87 console.error("Server error:", err);88 }89});9091// 3. Start server92const PORT = process.env.PORT || 3000;93server.listen(PORT, () => {94 console.log(`Server running at http://localhost:${PORT}`);95});9697// 4. Graceful shutdown98process.on("SIGTERM", () => {99 console.log("SIGTERM received. Shutting down gracefully...");100 server.close(() => {101 console.log("Server closed");102 process.exit(0);103 });104});
🏋️ Practice Exercise
Exercises:
- Build a complete HTTP server with GET, POST, PUT, DELETE routes for a "todos" resource
- Add query parameter parsing for pagination (
?page=2&limit=10) - Implement request body parsing for JSON and URL-encoded form data
- Add request logging middleware that logs method, URL, status code, and response time
- Serve static files (HTML, CSS, JS) from a
public/directory with proper MIME types - Implement rate limiting — max 100 requests per minute per IP address
⚠️ Common Mistakes
Forgetting to call
res.end()— the client hangs forever waiting for a response, eventually timing outSetting headers after
res.write()orres.end()— headers must be set before sending body; Node.js throws 'ERR_HTTP_HEADERS_SENT'Not handling the request body as a stream —
req.bodydoesn't exist by default; you must listen fordataandendevents to collect the bodyNot setting
Content-Typeheaders — browsers and API clients may misinterpret the response without proper content typeUsing
http.createServer()for production without a reverse proxy — always put nginx or a load balancer in front for SSL, compression, and safety
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for The http Module & Creating Servers. Login to unlock this feature.