HTTP Basics and Express
HTTP Basics and Express
When you build an AI-powered application, you need a way for the frontend (what users see) to communicate with the backend (where your code runs). That communication happens over HTTP, and Express.js is the most popular tool for building HTTP servers in Node.js.
What is HTTP?
HTTP (HyperText Transfer Protocol) is the language that web browsers and servers use to talk to each other. Every time you visit a website, your browser sends an HTTP request and the server sends back an HTTP response.
HTTP Methods
Every request has a method that describes what you want to do:
| Method | Purpose | Example |
|---|---|---|
GET | Read / retrieve data | Get a list of users |
POST | Create new data | Create a new user |
PUT | Update / replace data | Update a user's profile |
PATCH | Partially update data | Change just the user's name |
DELETE | Remove data | Delete a user |
HTTP Status Codes
The server responds with a status code that tells you what happened:
| Code | Meaning | When You'll See It |
|---|---|---|
200 | OK — success | Data returned successfully |
201 | Created | New resource was created |
204 | No Content | Success, but nothing to return (e.g., delete) |
400 | Bad Request | You sent invalid data |
401 | Unauthorized | You need to log in |
403 | Forbidden | You don't have permission |
404 | Not Found | The resource doesn't exist |
500 | Internal Server Error | Something broke on the server |
The Request-Response Cycle
Browser (Client) Server
| |
| ── GET /api/users ──────> |
| | (Looks up users in database)
| <── 200 OK [{...}, {...}] ── |
| |
| ── POST /api/users ─────> |
| { name: "Alice" } | (Creates new user)
| <── 201 Created {id: 3} ─── |
The Built-in http Module (Brief)
Node.js has a built-in http module. It works but is very low-level:
import http from "http"; const server = http.createServer((req, res) => { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ message: "Hello!" })); }); server.listen(3000, () => { console.log("Server running on port 3000"); });
This is fine for understanding the concept, but nobody builds real applications this way. Instead, we use Express.
Express.js Introduction
Express is a framework built on top of the http module that makes building servers much easier. It's the most popular Node.js web framework with millions of downloads per week.
Installation
npm install express npm install -D @types/express # TypeScript types
Your First Express Server
import express from "express"; const app = express(); // Parse JSON request bodies app.use(express.json()); // Define a route app.get("/", (req, res) => { res.json({ message: "Hello from Express!" }); }); // Start the server app.listen(3000, () => { console.log("Server running at http://localhost:3000"); });
Run it with node server.js (or npx ts-node server.ts for TypeScript), then open http://localhost:3000 in your browser.
Routes
Routes define what happens when someone visits a specific URL with a specific HTTP method:
import express from "express"; const app = express(); app.use(express.json()); // GET /api/users — Get all users app.get("/api/users", (req, res) => { res.json([ { id: 1, name: "Alice" }, { id: 2, name: "Bob" }, ]); }); // GET /api/users/:id — Get one user by ID app.get("/api/users/:id", (req, res) => { const userId = req.params.id; res.json({ id: userId, name: "Alice" }); }); // POST /api/users — Create a user app.post("/api/users", (req, res) => { const { name, email } = req.body; // Save to database... res.status(201).json({ id: 3, name, email }); }); // PUT /api/users/:id — Update a user app.put("/api/users/:id", (req, res) => { const userId = req.params.id; const updates = req.body; // Update in database... res.json({ id: userId, ...updates }); }); // DELETE /api/users/:id — Delete a user app.delete("/api/users/:id", (req, res) => { const userId = req.params.id; // Delete from database... res.status(204).send(); }); app.listen(3000);
What to ask your AI: "Build a REST API with Express for a [resource]. Include GET (all), GET (one), POST, PUT, and DELETE endpoints."
Middleware
Middleware functions run before your route handler. They can modify the request, check permissions, log information, and more.
import express from "express"; const app = express(); // Built-in middleware: parse JSON bodies app.use(express.json()); // Custom middleware: log every request app.use((req, res, next) => { console.log(`${req.method} ${req.path}`); next(); // Call next() to continue to the route handler }); // Custom middleware: check for API key const requireApiKey = (req, res, next) => { const apiKey = req.headers["x-api-key"]; if (!apiKey || apiKey !== process.env.API_KEY) { return res.status(401).json({ error: "Invalid API key" }); } next(); }; // Apply middleware to specific routes app.get("/api/public", (req, res) => { res.json({ message: "Anyone can access this" }); }); app.get("/api/protected", requireApiKey, (req, res) => { res.json({ message: "Only requests with a valid API key" }); });
Common Middleware Packages
| Package | Purpose |
|---|---|
cors | Allow requests from other domains (frontend to backend) |
helmet | Security headers |
morgan | Request logging |
express-rate-limit | Limit requests per IP |
multer | File upload handling |
import cors from "cors"; import helmet from "helmet"; app.use(cors()); // Allow cross-origin requests app.use(helmet()); // Add security headers
Request and Response Objects
The Request Object (req)
app.get("/api/search", (req, res) => { req.params; // URL parameters — /users/:id -> { id: "123" } req.query; // Query string — /search?q=hello -> { q: "hello" } req.body; // Request body — POST data (JSON) req.headers; // Request headers — { "content-type": "application/json" } req.method; // HTTP method — "GET", "POST", etc. req.path; // URL path — "/api/search" });
The Response Object (res)
app.get("/api/example", (req, res) => { res.json({ data: "Send JSON" }); // Most common res.status(201).json({ id: 1 }); // Set status code + JSON res.status(404).json({ error: "Not found" }); res.send("Plain text response"); // Send plain text res.status(204).send(); // No content res.redirect("/other-page"); // Redirect });
Building a Simple REST API
Here's a complete, working API that you could use as a starting point:
import express from "express"; import cors from "cors"; const app = express(); app.use(cors()); app.use(express.json()); // In-memory data store (use a real database in production) let todos = [ { id: 1, text: "Learn Node.js", done: false }, { id: 2, text: "Build an API", done: false }, ]; let nextId = 3; // GET all todos app.get("/api/todos", (req, res) => { res.json(todos); }); // POST a new todo app.post("/api/todos", (req, res) => { const { text } = req.body; const todo = { id: nextId++, text, done: false }; todos.push(todo); res.status(201).json(todo); }); // PUT (update) a todo app.put("/api/todos/:id", (req, res) => { const id = parseInt(req.params.id); const todo = todos.find((t) => t.id === id); if (!todo) return res.status(404).json({ error: "Not found" }); Object.assign(todo, req.body); res.json(todo); }); // DELETE a todo app.delete("/api/todos/:id", (req, res) => { const id = parseInt(req.params.id); todos = todos.filter((t) => t.id !== id); res.status(204).send(); }); app.listen(3000, () => { console.log("API running at http://localhost:3000"); });
Serving Static Files
Express can also serve files (HTML, CSS, images) directly:
import path from "path"; // Serve files from the "public" folder app.use(express.static("public")); // Now files in public/ are accessible: // public/index.html -> http://localhost:3000/index.html // public/style.css -> http://localhost:3000/style.css
What's Next?
You now understand HTTP and can build APIs with Express. The next tutorial covers async JavaScript in Node.js — how to handle operations that take time (API calls, database queries, file reads) without blocking your server.
What to ask your AI: "Build an Express API for my [app idea]. It needs endpoints for [describe your data and operations]."