Books/Node.js Essentials/HTTP Basics and Express

    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:

    MethodPurposeExample
    GETRead / retrieve dataGet a list of users
    POSTCreate new dataCreate a new user
    PUTUpdate / replace dataUpdate a user's profile
    PATCHPartially update dataChange just the user's name
    DELETERemove dataDelete a user

    HTTP Status Codes

    The server responds with a status code that tells you what happened:

    CodeMeaningWhen You'll See It
    200OK — successData returned successfully
    201CreatedNew resource was created
    204No ContentSuccess, but nothing to return (e.g., delete)
    400Bad RequestYou sent invalid data
    401UnauthorizedYou need to log in
    403ForbiddenYou don't have permission
    404Not FoundThe resource doesn't exist
    500Internal Server ErrorSomething 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

    PackagePurpose
    corsAllow requests from other domains (frontend to backend)
    helmetSecurity headers
    morganRequest logging
    express-rate-limitLimit requests per IP
    multerFile 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]."


    🌐 www.genai-mentor.ai