CMD Simulator

How to Type API Responses with Generated Interfaces

Step-by-step guide to converting REST API JSON responses into typed TypeScript interfaces and C# classes. Includes fetch examples, error handling, and best practices.

Why Type Your API Responses?

Untyped API responses are a major source of runtime errors. When you access response.data.users[0].name without types, TypeScript can't tell you if users exists or if it's an array.

By generating interfaces from your API's JSON response, you get:

  • Compile-time error detection
  • IDE auto-complete for all fields
  • Refactoring safety when API shapes change
  • Self-documenting code that describes the data structure

Step-by-Step Workflow

1. Capture a Sample Response

Use your browser DevTools, Postman, or curl to capture a real JSON response:

curl https://api.example.com/users/1 | json_pp

2. Paste into the Converter

Copy the JSON response and paste it into our JSON to Typedef Converter. Set the root name to something meaningful like UserResponse.

3. Copy and Use the Generated Types

TypeScript Example

// types/api.ts (paste generated interfaces here)
export interface Address {
  street: string;
  city: string;
  zipCode: string;
}

export interface UserResponse {
  id: number;
  name: string;
  email: string;
  address: Address;
  tags: string[];
}

// api/users.ts
export async function getUser(id: number): Promise<UserResponse> {
  const res = await fetch(\`/api/users/\${id}\`);
  if (!res.ok) throw new Error("Failed to fetch user");
  return res.json() as Promise<UserResponse>;
}

// Now you get full type safety:
const user = await getUser(1);
console.log(user.address.city);  // ✅ auto-complete works
console.log(user.phone);         // ❌ compile error — property doesn't exist

C# Example

// Models/UserResponse.cs (paste generated classes)
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}

public class UserResponse
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public Address Address { get; set; }
    public List<string> Tags { get; set; }
}

// Usage with HttpClient
var response = await httpClient.GetFromJsonAsync<UserResponse>("/api/users/1");
Console.WriteLine(response.Address.City);  // fully typed

Handling Paginated Responses

Many APIs wrap data in pagination envelopes:

{
  "data": [{ "id": 1, "name": "Alice" }],
  "total": 100,
  "page": 1,
  "perPage": 10
}

Set the root name to PaginatedUserResponse to get a clean, descriptive type.


Best Practices

  1. Use multiple sample responses — Convert several responses and merge the types to catch optional fields
  2. Name root types descriptivelyGetUsersResponse, CreateOrderRequest, etc.
  3. Separate request and response types — Don't reuse the same interface for both
  4. Version your types — When APIs change, regenerate and compare
  5. Add JSDoc comments — Annotate generated interfaces with API documentation

Ready to try it?

Open the Converter →