Node.js HTTP Server
The built-in http module lets Node.js act as a web server that answers requests from browsers and apps.
How a Web Server Works
- A browser sends a request, for example
GET /courses - The server reads the request: the method, the URL and any data
- The server sends back a response: a status code, headers and a body (HTML, JSON or a file)
Your First Server
Create server.js:
Example
import http from "node:http";
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end("Assalam o Alaikum! This page comes from Node.js.");
});
server.listen(3000, () => {
console.log("Server running at http://localhost:3000/");
});Example
node server.jsServer running at http://localhost:3000/
Open http://localhost:3000/ in your browser and you will see the message. The program keeps running and waits for more requests. Press Ctrl + C to stop it.
createServertakes a function that runs for every requestreq(request) holds information about what the browser asked forres(response) is what you send backres.end()finishes the response. If you forget it, the browser keeps loading forever
The Request Object
| Property | Example value |
|---|---|
req.method | "GET", "POST" |
req.url | "/courses?city=karachi" |
req.headers | An object with headers like user-agent |
Routing by URL
Check req.url and req.method to send different responses:
Example
import http from "node:http";
const courses = [
{ id: 1, name: "Web Development", months: 6 },
{ id: 2, name: "Graphic Designing", months: 3 },
];
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (req.method === "GET" && url.pathname === "/") {
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end("<h1>Workownix</h1><p>See <a href='/api/courses'>our courses</a>.</p>");
} else if (req.method === "GET" && url.pathname === "/api/courses") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(courses));
} else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Page not found");
}
});
server.listen(3000);Visiting http://localhost:3000/api/courses shows:
[{"id":1,"name":"Web Development","months":6},{"id":2,"name":"Graphic Designing","months":3}]new URL(...) splits the address into parts. url.pathname is the path, and url.searchParams.get("city") reads a query value like ?city=karachi.
Status Codes
| Code | Meaning |
|---|---|
| 200 | OK, everything worked |
| 201 | Created, new data was saved |
| 301 | Moved permanently to another URL |
| 400 | Bad request, the data sent was wrong |
| 401 | Not logged in |
| 404 | Not found |
| 500 | Server error, something broke in your code |
Reading POST Data
The body of a request arrives in pieces, so you collect it. In modern Node.js you can loop over the request with for await:
Example
import http from "node:http";
const server = http.createServer(async (req, res) => {
if (req.method === "POST" && req.url === "/api/contact") {
let body = "";
for await (const chunk of req) {
body += chunk;
}
const data = JSON.parse(body);
console.log("Message from", data.name);
res.writeHead(201, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true, message: `Thanks ${data.name}!` }));
return;
}
res.writeHead(404);
res.end();
});
server.listen(3000);You can test it from another terminal with curl:
Example
curl -X POST http://localhost:3000/api/contact -H "Content-Type: application/json" -d "{\"name\":\"Sana\"}"{"ok":true,"message":"Thanks Sana!"}In a real app, wrap JSON.parse in try/catch and reply with status 400 if the data is not valid JSON. Otherwise one bad request can crash your server.
Why Use a Framework?
As you can see, routing and reading data by hand takes a lot of code. Frameworks like Express do this work for you. You will use Express in the next lesson, and it is built on top of this same http module.
Exercise
Exercise
What happens if your request handler never calls res.end()?
