Lesson 73 of 60 – Interfaces for API Data
100%

Interfaces for API Data

React Native applications commonly receive data from APIs. The response may contain users, products, students, posts, orders, messages, or other information.

TypeScript interfaces allow us to describe the structure of API data and use that structure consistently throughout the application.

Note: An interface describes the structure we expect API data to have. It does not automatically validate unknown JSON at runtime.

1. What is API Data?

API data is information returned by a server after an application sends a request.

{
    "id": 101,
    "name": "Rahul",
    "email": "rahul@example.com"
}

This data can be displayed and processed inside a React Native application.

2. Why Use Interfaces for API Data?

  • Defines the expected API structure.
  • Improves code completion.
  • Helps detect incorrect property names.
  • Makes API functions easier to understand.
  • Allows the same structure to be reused.
  • Improves application maintainability.

3. Creating an API Interface

interface User {
    id: number;
    name: string;
    email: string;
}

This interface describes the expected structure of a user returned by an API.

4. Creating API Data Using an Interface

const user: User = {
    id: 101,
    name: "Rahul",
    email: "rahul@example.com"
};

TypeScript checks that the object follows the User interface.

5. API Interface with More Properties

interface Student {
    id: number;
    name: string;
    email: string;
    course: string;
    fee: number;
}

Interfaces can contain multiple properties with different types.

6. API Interface with Boolean Values

interface User {
    id: number;
    name: string;
    active: boolean;
}

Boolean properties can represent values such as active, verified, enabled, or completed.

7. Optional API Properties

Some API fields may not be available for every record.

interface User {
    id: number;
    name: string;
    email: string;
    phone?: string;
}

The phone property is optional.

8. Readonly API Properties

A property can be marked as readonly when it should not be reassigned through the typed object.

interface User {
    readonly id: number;
    name: string;
    email: string;
}

9. Nested API Objects

API responses frequently contain nested objects.

interface Address {
    city: string;
    state: string;
    pincode: string;
}

interface User {
    id: number;
    name: string;
    address: Address;
}

10. Example Nested API Data

const user: User = {
    id: 101,
    name: "Rahul",
    address: {
        city: "Patna",
        state: "Bihar",
        pincode: "800001"
    }
};

The nested address must follow the Address interface.

11. API Response Interface

An API response may contain additional information along with the actual data.

interface UserResponse {
    success: boolean;
    user: User;
}

This interface describes both the success value and user data.

12. API Response with an Array

interface UserResponse {
    success: boolean;
    users: User[];
}

The users property contains an array of User objects.

13. Using an Interface with fetch()

const response =
    await fetch(
        "https://example.com/api/users"
    );

const data: User[] =
    await response.json();

The response data can be represented as an array of User objects.

14. Typed API Function

async function getUsers():
    Promise<User[]> {

    const response =
        await fetch(
            "https://example.com/api/users"
        );

    const data: User[] =
        await response.json();

    return data;
}

The return type tells TypeScript that the function returns a Promise containing an array of User objects.

15. Interface with useState

const [users, setUsers] =
    useState<User[]>([]);

This tells TypeScript that the state contains an array of User objects.

16. Nullable API State

When a single API record has not been loaded yet, the state can be nullable.

const [user, setUser] =
    useState<User | null>(null);

The state can contain either a User object or null.

17. Loading and Error States

const [loading, setLoading] =
    useState<boolean>(false);

const [error, setError] =
    useState<string | null>(null);

Separate states can be used to represent loading and error conditions.

18. API Interface with Union Types

API properties can sometimes have a limited set of possible values.

interface User {
    id: number;
    name: string;
    role: "admin" | "student" | "teacher";
}

Only the specified role values are allowed by the interface.

19. API Interface with Dates

APIs commonly return dates as strings.

interface User {
    id: number;
    name: string;
    createdAt: string;
}

For example, the API might return:

{
    "createdAt": "2026-09-30T10:30:00Z"
}

20. API Interface for Products

interface Product {
    id: number;
    name: string;
    price: number;
    available: boolean;
}

The same interface approach can be used for products, orders, posts, messages, or any other API resource.

21. Displaying Typed API Data

{users.map((user: User) => (

    <View key={user.id}>

        <Text>
            {user.name}
        </Text>

        <Text>
            {user.email}
        </Text>

    </View>

))}

TypeScript understands the properties available on each user.

22. API Interfaces with FlatList

<FlatList<User>
    data={users}
    keyExtractor={(item) =>
        item.id.toString()
    }
    renderItem={({ item }) => (

        <View>

            <Text>
                {item.name}
            </Text>

            <Text>
                {item.email}
            </Text>

        </View>

    )}
/>

23. API Interfaces as Component Props

interface UserCardProps {
    user: User;
}

function UserCard(
    { user }: UserCardProps
): React.JSX.Element {

    return (
        <View>

            <Text>
                {user.name}
            </Text>

            <Text>
                {user.email}
            </Text>

        </View>
    );
}

This allows a reusable component to receive correctly typed API data.

24. Common API Interface Mistakes

  • Using any for every API response.
  • Using the wrong property name.
  • Using the wrong property type.
  • Forgetting optional properties.
  • Assuming every API response has the same structure.
  • Forgetting to type arrays.
  • Assuming TypeScript validates external JSON at runtime.

25. Separating API Types into Files

In a larger React Native project, API interfaces can be stored in a dedicated types folder.

// types/User.ts

export interface User {
    id: number;
    name: string;
    email: string;
}

Keeping shared types in separate files makes them easier to reuse.

26. Importing API Interfaces

import {
    User
} from "./types/User";

The same User interface can now be used by API functions, components, screens, and state.

27. API Response with Pagination

Some APIs return pagination information along with the records.

interface UserResponse {
    success: boolean;
    users: User[];
    page: number;
    totalPages: number;
}

This interface describes both the user data and pagination information.

28. Complete API Interface Example

import React, {
    useEffect,
    useState
} from "react";

import {
    View,
    Text,
    FlatList,
    ActivityIndicator
} from "react-native";

interface User {
    readonly id: number;
    name: string;
    email: string;
    phone?: string;
    role: "admin" | "student" | "teacher";
}

interface UserResponse {
    success: boolean;
    users: User[];
}

export default function App(): React.JSX.Element {

    const [users, setUsers] =
        useState<User[]>([]);

    const [loading, setLoading] =
        useState<boolean>(true);

    const [error, setError] =
        useState<string | null>(null);

    const loadUsers =
        async (): Promise<void> => {

        try {

            setLoading(true);
            setError(null);

            const response =
                await fetch(
                    "https://example.com/api/users"
                );

            if (!response.ok) {
                throw new Error(
                    "Request failed"
                );
            }

            const data: UserResponse =
                await response.json();

            setUsers(data.users);

        } catch (error) {

            setError(
                "Unable to load users"
            );

        } finally {

            setLoading(false);

        }
    };

    useEffect(() => {

        loadUsers();

    }, []);

    if (loading) {

        return (
            <View>
                <ActivityIndicator />
            </View>
        );

    }

    if (error) {

        return (
            <View>
                <Text>{error}</Text>
            </View>
        );

    }

    return (
        <View>

            <Text>
                User List
            </Text>

            <FlatList<User>
                data={users}

                keyExtractor={(item) =>
                    item.id.toString()
                }

                renderItem={({ item }) => (

                    <View>

                        <Text>
                            {item.name}
                        </Text>

                        <Text>
                            {item.email}
                        </Text>

                        <Text>
                            Role: {item.role}
                        </Text>

                        <Text>
                            Phone: {
                                item.phone ??
                                "Not available"
                            }
                        </Text>

                    </View>

                )}
            />

        </View>
    );
}

29. Best Practices for API Interfaces

  • Create interfaces for important API resources.
  • Use meaningful interface and property names.
  • Use optional properties when a field may be missing.
  • Use union types for fixed API values.
  • Use Promise<Type> for typed asynchronous functions.
  • Keep shared API interfaces in a dedicated types folder.
  • Reuse the same interfaces across API, state, components, and FlatList.
  • Use runtime validation when the application requires validation of untrusted API data.

30. Summary

Interfaces make API data easier to understand and safer to use in React Native applications. An interface can describe individual records, arrays, nested objects, API response wrappers, pagination information, optional properties, and fixed values.

You should now understand how to create API interfaces, use them with fetch(), Promise return types, useState, FlatList, reusable components, pagination, and shared type files.

📌 Key Points

  • Use interfaces to describe API response structures.
  • Use User[] for arrays of API records.
  • Use nested interfaces for nested API objects.
  • Use Promise<Type> for typed API functions.
  • Use Type | null for data that may not be loaded yet.
  • Use optional properties for fields that may be missing.
  • Reuse API interfaces with state, FlatList, and components.
  • Remember that TypeScript types do not automatically validate external JSON at runtime.

🧠 Quick Quiz

Question: Which interface correctly represents an API response containing multiple User objects?