Lesson 117 of 158 – Typed API Responses
74%

Typed API Responses

In a React Native application using TypeScript, API responses can be strongly typed so that the application knows exactly what data is returned by the REST API.

Note: Typed API responses are useful when working with PHP/MySQL REST APIs, Axios, Fetch, FlatList, authentication, pagination, and other API operations.

1. What is a Typed API Response?

A typed API response means we define the expected structure of data returned by an API using TypeScript.

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

TypeScript can then use this structure when processing API data.

2. Why Type API Responses?

  • Improves type safety.
  • Provides better code completion.
  • Reduces property name mistakes.
  • Makes API code easier to understand.
  • Helps maintain large React Native projects.
  • Makes API data easier to use with FlatList.

3. Simple API Response

Suppose the PHP API returns:

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

We can define:

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

4. API Response with Success and Message

A REST API often returns a structure like:

{
    "success": true,
    "message": "Student fetched successfully",
    "data": {
        "id": 1,
        "name": "Rahul"
    }
}

We can create separate interfaces for this response.

5. Creating a Student Interface

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

This interface represents the student object inside the API response.

6. Creating a Response Interface

interface StudentResponse {
    success: boolean;
    message: string;
    data: Student;
}

Here, data contains one Student object.

7. Typed Axios GET Response

Axios supports TypeScript generics for typing response data.

const response =
    await api.get<StudentResponse>(
        "/students/1"
    );

TypeScript now knows the expected structure of response.data.

8. Accessing Typed Response Data

const response =
    await api.get<StudentResponse>(
        "/students/1"
    );

console.log(response.data.success);
console.log(response.data.message);
console.log(response.data.data.name);

TypeScript can provide suggestions for these properties.

9. API Response Containing Multiple Students

A list endpoint usually returns an array of records.

{
    "success": true,
    "message": "Students fetched successfully",
    "data": [
        {
            "id": 1,
            "name": "Rahul"
        },
        {
            "id": 2,
            "name": "Amit"
        }
    ]
}

10. Typed Array Response

interface StudentListResponse {
    success: boolean;
    message: string;
    data: Student[];
}

Student[] means that the data property contains an array of Student objects.

11. Typed Axios List Request

const response =
    await api.get<StudentListResponse>(
        "/students"
    );

const students = response.data.data;

The students variable is understood as Student[].

12. Using Typed Data with FlatList

<FlatList
    data={students}
    keyExtractor={item => item.id.toString()}
    renderItem={({ item }) => (
        <Text>{item.name}</Text>
    )}
/>

TypeScript knows that each FlatList item is a Student.

13. Nested API Response

APIs can return nested objects.

{
    "success": true,
    "data": {
        "student": {
            "id": 1,
            "name": "Rahul"
        }
    }
}

Each nested level can be represented with a TypeScript interface.

14. Nested Response Interfaces

interface Student {
    id: number;
    name: string;
}

interface StudentData {
    student: Student;
}

interface StudentResponse {
    success: boolean;
    data: StudentData;
}

15. Typed Login Response

Authentication APIs can also have typed responses.

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

interface LoginResponse {
    success: boolean;
    message: string;
    token: string;
    user: LoginUser;
}

16. Typed Login Request with Axios

const response =
    await api.post<LoginResponse>(
        "/login",
        {
            email: "user@example.com",
            password: "123456"
        }
    );

const token = response.data.token;

17. Typed API Response with useState

const [student, setStudent] =
    useState<Student | null>(null);

The state can contain either a Student object or null.

setStudent(response.data.data);

18. Typed API Response with Loading State

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

const [students, setStudents] =
    useState<Student[]>([]);

TypeScript can type both API data and UI state.

19. Typed API Error Response

Error responses can also have a standard structure.

{
    "success": false,
    "message": "Validation failed",
    "errors": {
        "email": [
            "Email is required"
        ]
    }
}

We can describe it using:

interface ApiErrorResponse {
    success: boolean;
    message: string;
    errors?: {
        [key: string]: string[];
    };
}

20. Typed Pagination Response

Pagination responses normally contain both records and metadata.

interface PaginationMeta {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
}

interface StudentListResponse {
    success: boolean;
    message: string;
    data: Student[];
    meta: PaginationMeta;
}

21. Reading Pagination Data

const response =
    await api.get<StudentListResponse>(
        "/students?page=1&limit=10"
    );

const students = response.data.data;
const currentPage = response.data.meta.page;
const totalPages = response.data.meta.totalPages;

TypeScript understands the structure of the complete response.

22. Typed Search Response

Search APIs can use the same response interface.

const response =
    await api.get<StudentListResponse>(
        "/students",
        {
            params: {
                search: "Rahul"
            }
        }
    );

The returned data remains strongly typed as Student objects.

23. Typed POST Response

A POST API can return the newly created student.

interface CreateStudentResponse {
    success: boolean;
    message: string;
    data: Student;
}
const response =
    await api.post<CreateStudentResponse>(
        "/students",
        studentData
    );

console.log(response.data.data.id);

24. Typed PUT Response

interface UpdateStudentResponse {
    success: boolean;
    message: string;
    data: Student;
}

const response =
    await api.put<UpdateStudentResponse>(
        "/students/1",
        studentData
    );

console.log(response.data.message);

25. Typed DELETE Response

A DELETE endpoint can also return a standard response.

interface DeleteResponse {
    success: boolean;
    message: string;
}

const response =
    await api.delete<DeleteResponse>(
        "/students/1"
    );

console.log(response.data.message);

26. Generic API Response

If many API responses use the same structure, a generic interface can reduce repetition.

interface ApiResponse<T> {
    success: boolean;
    message: string;
    data: T;
}

The T represents the type of data returned by the API.

27. Using the Generic Response

For one student:

type StudentResponse =
    ApiResponse<Student>;

For multiple students:

type StudentListResponse =
    ApiResponse<Student[]>;

This allows the same response structure to be reused with different data types.

28. Complete Typed GET Example

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

interface StudentListResponse {
    success: boolean;
    message: string;
    data: Student[];
}

const loadStudents = async () => {

    try {

        const response =
            await api.get<StudentListResponse>(
                "/students"
            );

        setStudents(response.data.data);

    } catch (error) {

        console.log("Failed to load students");

    }
};

29. Complete React Native API Example

import React, { useEffect, useState } from "react";
import { View, Text, FlatList } from "react-native";
import api from "./api";

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

interface StudentListResponse {
    success: boolean;
    message: string;
    data: Student[];
}

const StudentList = () => {

    const [students, setStudents] =
        useState<Student[]>([]);

    useEffect(() => {

        const loadStudents = async () => {

            try {

                const response =
                    await api.get<StudentListResponse>(
                        "/students"
                    );

                setStudents(response.data.data);

            } catch (error) {

                console.log(error);

            }

        };

        loadStudents();

    }, []);

    return (
        <View>

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

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

                )}
            />

        </View>
    );
};

export default StudentList;

30. Complete API Response Flow

PHP + MySQL
     ↓
REST API
     ↓
JSON Response
     ↓
Axios
     ↓
TypeScript Interface
     ↓
Typed API Response
     ↓
React Native State
     ↓
FlatList / UI

For example, the PHP API can return:

{
    "success": true,
    "message": "Students fetched successfully",
    "data": [
        {
            "id": 1,
            "name": "Rahul",
            "email": "rahul@example.com"
        }
    ]
}

React Native can receive this response through Axios and use a TypeScript interface to describe its structure.

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

interface StudentListResponse {
    success: boolean;
    message: string;
    data: Student[];
}

const response =
    await api.get<StudentListResponse>(
        "/students"
    );

This creates a clear and type-safe connection between the PHP REST API and the React Native application.

📌 Key Points

  • Typed API responses describe the structure of JSON returned by an API.
  • TypeScript interfaces improve API type safety.
  • Axios supports typed responses using generics.
  • Use Student[] when the API returns multiple students.
  • Nested API data can be represented using nested interfaces.
  • Login, POST, PUT, DELETE, and pagination responses can all be typed.
  • API error responses can also have their own interfaces.
  • Generic interfaces can be reused for different API data types.
  • Typed responses work well with React Native state and FlatList.
  • The TypeScript interface should match the actual API response structure.

🧠 Quick Quiz

Question: Which Axios syntax is used to specify the TypeScript type of an API response?