Books/TypeScript Essentials/TypeScript for Backend (Node.js)

    TypeScript for Backend (Node.js)

    TypeScript for Backend (Node.js)

    When you ask AI to build an API or backend service, it will typically generate a Node.js server with TypeScript. This tutorial covers the patterns you'll see in backend code.

    Backend Frameworks

    AI will likely use one of these popular Node.js frameworks:

    FrameworkStyleWhen You'll See It
    ExpressMinimal, flexibleMost common, lots of examples
    Next.js API RoutesFile-based routingIf you're already using Next.js
    FastifyFast, schema-basedPerformance-focused projects
    HonoLightweight, modernEdge/serverless projects

    The concepts are similar across all of them. We'll use Express for examples since it's the most common.

    A Basic Express Server

    import express, { Request, Response } from "express";
    
    const app = express();
    app.use(express.json()); // Parse JSON request bodies
    
    // A simple route
    app.get("/api/hello", (req: Request, res: Response) => {
      res.json({ message: "Hello, World!" });
    });
    
    app.listen(3000, () => {
      console.log("Server running on port 3000");
    });

    Key things to notice:

    • Request and Response are imported from Express — these are the TypeScript types
    • req contains the incoming request (URL, headers, body)
    • res is used to send a response back
    • .json() sends a JSON response

    Typed Request and Response

    For real APIs, you'll want to type what the request and response look like:

    // Define your data shapes
    interface CreateUserBody {
      name: string;
      email: string;
      password: string;
    }
    
    interface UserResponse {
      id: string;
      name: string;
      email: string;
      createdAt: string;
    }
    
    // Type the route handler
    app.post("/api/users", async (req: Request<{}, {}, CreateUserBody>, res: Response<UserResponse>) => {
      const { name, email, password } = req.body; // TypeScript knows these fields exist
    
      // Create user in database...
      const user: UserResponse = {
        id: "abc123",
        name,
        email,
        createdAt: new Date().toISOString(),
      };
    
      res.status(201).json(user);
    });

    What to ask your AI: "Create a REST API endpoint for [resource]. It should accept [these fields] and return [this data]."

    Route Parameters and Query Strings

    URL Parameters

    // Route: /api/users/:id
    app.get("/api/users/:id", async (req: Request<{ id: string }>, res: Response) => {
      const userId = req.params.id; // TypeScript knows 'id' exists and is a string
    
      // Fetch user from database...
      res.json(user);
    });

    Query Parameters

    // Route: /api/products?category=electronics&page=2
    interface ProductQuery {
      category?: string;
      page?: string;
      limit?: string;
    }
    
    app.get("/api/products", async (req: Request<{}, {}, {}, ProductQuery>, res: Response) => {
      const { category, page = "1", limit = "10" } = req.query;
    
      // Fetch products with filters...
      res.json(products);
    });

    CRUD API Pattern

    The most common thing you'll ask AI to build is a CRUD API (Create, Read, Update, Delete). Here's the pattern:

    interface Product {
      id: string;
      name: string;
      price: number;
      description: string;
    }
    
    type CreateProductInput = Omit<Product, "id">;
    
    // CREATE — POST /api/products
    app.post("/api/products", async (req: Request<{}, {}, CreateProductInput>, res: Response) => {
      const product = await db.createProduct(req.body);
      res.status(201).json(product);
    });
    
    // READ ALL — GET /api/products
    app.get("/api/products", async (req: Request, res: Response) => {
      const products = await db.getProducts();
      res.json(products);
    });
    
    // READ ONE — GET /api/products/:id
    app.get("/api/products/:id", async (req: Request<{ id: string }>, res: Response) => {
      const product = await db.getProduct(req.params.id);
      if (!product) return res.status(404).json({ error: "Not found" });
      res.json(product);
    });
    
    // UPDATE — PUT /api/products/:id
    app.put("/api/products/:id", async (req: Request<{ id: string }, {}, Partial<CreateProductInput>>, res: Response) => {
      const product = await db.updateProduct(req.params.id, req.body);
      res.json(product);
    });
    
    // DELETE — DELETE /api/products/:id
    app.delete("/api/products/:id", async (req: Request<{ id: string }>, res: Response) => {
      await db.deleteProduct(req.params.id);
      res.status(204).send();
    });

    What to ask your AI: "Build a complete CRUD API for [resource] with [these fields]. Include proper error handling and TypeScript types."

    Useful TypeScript Utility Types for Backend

    You'll see these in AI-generated backend code:

    interface User {
      id: string;
      name: string;
      email: string;
      password: string;
      createdAt: Date;
    }
    
    // Omit — remove fields (great for hiding password in responses)
    type PublicUser = Omit<User, "password">;
    
    // Pick — select only certain fields
    type UserPreview = Pick<User, "id" | "name">;
    
    // Partial — make all fields optional (great for update endpoints)
    type UpdateUserInput = Partial<Omit<User, "id" | "createdAt">>;
    
    // Required — make all fields required
    type CompleteUser = Required<User>;
    UtilityWhat It DoesCommon Use
    Omit<T, keys>Remove fieldsHide sensitive data
    Pick<T, keys>Keep only these fieldsLightweight responses
    Partial<T>Make all fields optionalUpdate/patch endpoints
    Required<T>Make all fields requiredStrict validation

    What to ask your AI: "I have this User interface. Create a type for the API response that excludes the password field."

    Database Operations

    Whether using SQL (PostgreSQL, MySQL) or NoSQL (MongoDB, Firestore), the patterns are similar:

    // A typical database service
    interface TodoService {
      getAll(): Promise<Todo[]>;
      getById(id: string): Promise<Todo | null>;
      create(data: CreateTodoInput): Promise<Todo>;
      update(id: string, data: Partial<CreateTodoInput>): Promise<Todo>;
      delete(id: string): Promise<void>;
    }

    Notice the return types:

    • Promise<Todo[]> — returns multiple todos
    • Promise<Todo | null> — returns one todo or null (not found)
    • Promise<void> — returns nothing (just deletes)

    Middleware

    Middleware functions run before your route handler — for things like authentication, logging, or validation:

    import { Request, Response, NextFunction } from "express";
    
    // Authentication middleware
    const requireAuth = (req: Request, res: Response, next: NextFunction) => {
      const token = req.headers.authorization;
    
      if (!token) {
        return res.status(401).json({ error: "No token provided" });
      }
    
      // Verify token...
      next(); // Continue to the route handler
    };
    
    // Use it on specific routes
    app.get("/api/profile", requireAuth, (req, res) => {
      res.json({ user: req.user });
    });

    What to ask your AI: "Add authentication middleware to my API. Protect the [these routes] endpoints."

    Environment Variables

    Backend code often uses environment variables for secrets and configuration:

    // Type your environment variables
    interface Env {
      DATABASE_URL: string;
      JWT_SECRET: string;
      PORT: string;
    }
    
    // Access them safely
    const port = process.env.PORT || "3000";
    const dbUrl = process.env.DATABASE_URL;
    
    if (!dbUrl) {
      throw new Error("DATABASE_URL environment variable is required");
    }

    What to ask your AI: "Set up environment variable handling with a .env file. I need variables for [database URL, API key, etc.]."

    Prompts for Building Backend with AI

    API Setup:

    • "Create an Express server with TypeScript. Set up CORS, JSON parsing, and error handling middleware."
    • "Set up a Node.js project with TypeScript, Express, and [database]. Include the project structure and configuration files."

    Endpoints:

    • "Build a REST API for a blog with posts and comments. Posts have a title, body, author, and published date. Comments belong to a post."
    • "Create an authentication API with signup, login, and logout endpoints using JWT tokens."

    Database:

    • "Set up a database connection to [PostgreSQL/MongoDB/Firestore] with TypeScript types for all my models."
    • "Create database service functions for CRUD operations on [resource]."

    Security:

    • "Add input validation to my API endpoints using Zod. Validate the request body before processing."
    • "Add rate limiting and request logging to my Express server."

    What's Next?

    You now understand TypeScript on both frontend and backend. The final tutorial is your TypeScript Cheat Sheet — a quick reference with all the types and patterns, plus AI prompts organized by task.


    🌐 www.genai-mentor.ai