Huzi Blogs
BlogCategories
BlogCategories
Disclaimer & Data Privacy Policy
Project by huzi.pk

© 2026 blogs.huzi.pk. All Rights Reserved.

    Back to all posts
    Programming

    Building a REST API with Node.js and Express 5 (2026)

    By Huzi

    Express is still the shortest path from empty folder to working API, and version 5 finally makes it pleasant — async handlers reject properly and the legacy patterns are gone. Pair it with Node.js 22 LTS (native fetch, native .env loading via --env-file, a built-in test runner) plus TypeScript, and the stack is boring in the best way. Let's build it.

    Scaffold

    mkdir my-api && cd my-api
    npm init -y
    npm install express zod
    npm install -D typescript @types/node @types/express tsx
    npx tsc --init
    

    Then make it ESM with a hot-reloading dev script in package.json:

    {
      "type": "module",
      "scripts": {
        "dev": "tsx watch src/server.ts",
        "build": "tsc",
        "start": "node dist/server.js"
      }
    }
    

    Two habits save you an hour later: keep tsx in devDependencies so production installs stay lean, and set the module mode before writing your first import — mixing module systems is the classic day-one bug.

    The server

    import express from "express";
    
    const app = express();
    app.use(express.json());
    
    app.get("/", (_req, res) => {
      res.json({ message: "Hello, World!", version: "1.0.0" });
    });
    
    app.listen(3000, () => console.log("http://localhost:3000"));
    

    Note that app.use(express.json()) sits above the route — middleware runs top to bottom, and forgetting it is the classic reason a req.body arrives as undefined. Run npm run dev, open localhost, and that JSON greeting is your first endpoint.

    The router: CRUD with validation

    Real APIs live in routers, not the root file. Put this in src/routes/users.ts, then mount it with app.use("/api", router):

    import { Router } from "express";
    import { z } from "zod";
    
    const router = Router();
    type User = { id: number; name: string; email: string };
    const users: User[] = [
      { id: 1, name: "Alice", email: "[email protected]" },
      { id: 2, name: "Bob", email: "[email protected]" },
    ];
    let nextId = 3;
    
    const createUserSchema = z.object({
      name: z.string().min(2),
      email: z.string().email(),
    });
    
    router.get("/users", (_req, res) => res.json(users));
    
    router.post("/users", (req, res) => {
      const parsed = createUserSchema.safeParse(req.body);
      if (!parsed.success) {
        return res.status(400).json({ errors: parsed.error.issues });
      }
      const newUser: User = { id: nextId++, ...parsed.data };
      users.push(newUser);
      res.status(201).json(newUser);
    });
    
    router.delete("/users/:id", (req, res) => {
      const idx = users.findIndex((u) => u.id === Number(req.params.id));
      if (idx === -1) return res.status(404).json({ error: "User not found" });
      users.splice(idx, 1);
      res.status(204).send();
    });
    
    export default router;
    

    Notice the discipline: status codes that mean something (201 created, 404 missing, 204 after delete), and Zod rejecting bad input before it ever touches storage. A PUT route follows the same pattern — findIndex, replace, return the updated record — and it should be idempotent: calling it twice with the same body leaves the same state. Changing a single field is PATCH territory, and most real APIs end up supporting both. Everything else, from JWT auth to rate limiting, slots in later as middleware.

    One error handler

    app.use((err, _req, res, _next) => {
      console.error(err);
      res.status(500).json({ error: "Internal Server Error" });
    });
    

    Express 5 forwards rejected promises from async handlers here automatically, so this single middleware closes the loop.

    From array to database

    Swap the array for PostgreSQL with Drizzle (type-safe SQL, tiny footprint) or Prisma (the most ergonomic schema file), or MongoDB with Mongoose for flexible documents. The repository pattern is the bridge: replace the array with a couple of functions like listUsers and createUser, and the router barely notices. Keep controllers thin, put business logic in a service layer, and the database decision stops being architectural surgery — that is the point of the layering.

    There is a dignity in things that answer when asked. Gaza's engineers keep rebuilding water and power networks with whatever survives each round of destruction — infrastructure maintained as a refusal to give up.

    An API is a promise about behavior; so is a package. Our Umrah quotes at HTG Travels come with hotel names and distances in writing — no mystery hotel after landing in Makkah, and the price we quote is the price you pay.

    Advertisements


    You Might Also Like

    Glamorous Heavy Embroidered Net Bridal Suit 2026 | Tassel Daman

    Glamorous Heavy Embroidered Net Bridal Suit 2026 | Tassel Daman

    PKR 9400

    Luxury Heavy Embroidered Lawn Suit 3-Pc | Digital Print Silk Dupatta (2026 Collection)

    Luxury Heavy Embroidered Lawn Suit 3-Pc | Digital Print Silk Dupatta (2026 Collection)

    PKR 5750

    Trendy 2-Piece Embroidered Cotton Lawn Suit | Shirt & Trouser (2024)

    Trendy 2-Piece Embroidered Cotton Lawn Suit | Shirt & Trouser (2024)

    PKR 2950

    Digital Print Embroidered EID Lawn Suit (90/70) 3-Pc | Soft Chiffon Dupatta (2025)

    Digital Print Embroidered EID Lawn Suit (90/70) 3-Pc | Soft Chiffon Dupatta (2025)

    PKR 4450

    Trendy All-Over Digital Print Lawn 3-Pc Suit with Matching Lawn Dupatta (Casual)

    Trendy All-Over Digital Print Lawn 3-Pc Suit with Matching Lawn Dupatta (Casual)

    PKR 4250

    Advertisements


    Related Posts

    Programming
    The Architecture of Scale: Building REST APIs with Node.js (2026)
    The design layer of a professional API: resource naming, honest status codes, layered architecture, Zod boundaries, argon2 hashing, and correlation-ID error handling.

    By Huzi

    Read More
    Programming
    The Ultimate Beginner's Guide to Building a Website with Cloudflare Pages (2026)
    From an empty folder to a live site: git push, connect the repo in the dashboard, Pages Functions with D1 bindings, and the two fixes every beginner eventually needs.

    By Huzi

    Read More
    Programming
    Real-Time Revolution: Building Interactive Apps with WebSockets (2026)
    The 101 Switching Protocols handshake, choosing between polling, SSE and WebSockets, a working Yjs editor server, and the scaling and security rules that keep the bridge standing.

    By Huzi

    Read More
    Programming
    Introduction to GraphQL: A Modern Alternative to REST (2026)
    One endpoint, one query, exactly the fields you asked for: GraphQL's schema, queries, mutations and the 2026 @defer and @stream directives — and when REST is still the better call.

    By Huzi

    Read More
    Programming
    Demystifying REST APIs: A Beginner's Guide (2026)
    Resources with URLs, HTTP verbs as actions, status codes as the contract, and where REST sits next to GraphQL and gRPC in a 2026 backend.

    By Huzi

    Read More
    Programming
    The Beginner's Guide to React: Building the Modern Web (2026)
    The component mental model, one-way props, the server/client split that defines modern React, and the scaffolding commands to start a real project today.

    By Huzi

    Read More