Skip to Content
Course content

24: Practice Exercise: Typing a REST API Response Shape

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Wait, do I have to type the whole JSON object, or just the data I'm using?

Technically, you only need to type what you use. If the API sends back fifty fields but you only care about the user's email, you can just define those. But in my experience, that's a trap. When you're working on a professional team, typing the full expected shape of the response serves as documentation for everyone else. It tells the next developer, "This is what the backend actually sends."

Let's say we're hitting a Product Catalog API. Instead of a loose object, I'd define the specific entities first. Notice how I'm splitting the Price into its own type; it makes the code much cleaner than nesting everything in one giant block.

type Price = {
  amount: number;
  currency: 'USD' | 'EUR' | 'GBP';
};

interface Product {
  id: string;
  sku: string;
  name: string;
  description: string;
  price: Price;
  tags: string[];
}

Most APIs wrap their data in a "response envelope"—how do I handle that without repeating myself?

You'll rarely get a raw array or object back from a real-world API. Usually, you get a wrapper with things like status, page, or totalCount. If you create a new interface for every single endpoint, you're going to end up with a file that's 2,000 lines of redundant code.

The trick here is to use a Generic. I always create a standard ApiResponse type that can wrap any data shape. It's a lifesaver.

interface ApiResponse<T> {
  data: T;
  meta: {
    totalItems: number;
    currentPage: number;
    totalPages: number;
  };
  error?: {
    code: string;
    message: string;
  };
}

// Now, when I fetch a list of products, I just do this:
type ProductListResponse = ApiResponse<Product[]>;

// And if I fetch a single product by ID:
type ProductDetailResponse = ApiResponse<Product>;

What do I do when the API is inconsistent and some fields just... disappear?

This is where things get annoying. Some APIs send null, some omit the key entirely, and some send an empty string. To be safe, I lean heavily on optional properties (the ? operator). If a field isn't guaranteed 100% of the time, mark it optional. I'd rather TypeScript force me to check if a value exists now than have the app crash in production because of an undefined error.

Look at the description field in this updated version. Maybe some products don't have one. By marking it optional, TypeScript will remind me to use optional chaining (product.description?.toLowerCase()) when I actually use the data in a component.

interface Product {
  id: string;
  sku: string;
  name: string;
  description?: string; // Optional, because the API is flaky
  price: Price;
  tags: string[];
  discountPrice?: Price; // Only exists if the item is on sale
}



📋 Practical Task

Exercise: Typing the "Digital Library" API Response

You are integrating a library management API. The API returns a "Book Detail" response that includes the book's core information and a list of authors. Some books are "out of print," in which case the availableDate field is omitted from the response entirely.

Your Task: Create the following type definitions to match this JSON shape:

{
  "data": {
    "isbn": "978-3-16-148410-0",
    "title": "TypeScript Deep Dive",
    "publishedYear": 2021,
    "availableDate": "2023-12-01", 
    "authors": [
      { "id": "auth_1", "name": "Jane Doe" },
      { "id": "auth_2", "name": "John Smith" }
    ]
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": 1672531200
  }
}

Requirements:

  • Create an Author interface.
  • Create a Book interface (ensure availableDate is optional).
  • Create a generic ApiWrapper<T> interface to handle the data and meta fields.
  • Create a final type BookResponse that combines the wrapper and the book.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.