Lesson 103 of 158 – React Native API Error Handling
65%

React Native API Error Handling

API requests can fail for many reasons. The server may return an error, the internet connection may be unavailable, the user may not be authenticated, or the requested resource may not exist.

Note: In this lesson, we will learn how to handle REST API errors in React Native using Fetch, HTTP status codes, JSON error responses, try/catch, and user-friendly error messages.

1. What is API Error Handling?

API error handling means detecting API problems and responding to them correctly in the React Native application.

React Native
      ↓
   API Request
      ↓
   PHP REST API
      ↓
   Success / Error
      ↓
React Native handles result
      ↓
Show appropriate message

2. Why is Error Handling Important?

  • Prevents the application from crashing.
  • Shows useful messages to users.
  • Helps identify server problems.
  • Handles network failures.
  • Handles authentication problems.
  • Makes the application more reliable.

3. Common API Errors

Common API problems include:

  • Bad request
  • Unauthorized request
  • Forbidden request
  • Resource not found
  • Validation failure
  • Server error
  • Network failure
  • Timeout or unavailable server

4. HTTP Status Codes

HTTP status codes help the React Native application understand what happened with the request.

200 → Success
201 → Created
400 → Bad Request
401 → Unauthorized
403 → Forbidden
404 → Not Found
422 → Validation Error
500 → Server Error

5. Checking response.ok

Fetch provides the response.ok property to indicate whether the HTTP response is in the successful range.

const response = await fetch(
    API_URL
);

if (!response.ok) {

    console.log(
        "Request failed:",
        response.status
    );
}

6. Reading the HTTP Status

const response = await fetch(
    API_URL
);

console.log(
    response.status
);

The status can be used to perform different actions for different errors.

7. Handling 400 Bad Request

HTTP 400 generally means that the server could not process the request because the request was invalid.

if (response.status === 400) {

    Alert.alert(
        "Bad Request",
        "Please check the submitted data."
    );

    return;
}

8. Handling 401 Unauthorized

HTTP 401 commonly means that authentication is missing, invalid, or expired.

if (response.status === 401) {

    Alert.alert(
        "Session Expired",
        "Please login again."
    );

    return;
}

The application may then navigate the user to the login screen.

9. Handling 403 Forbidden

HTTP 403 means the server understood the request but the authenticated user does not have permission to perform the operation.

if (response.status === 403) {

    Alert.alert(
        "Access Denied",
        "You do not have permission."
    );

    return;
}

10. Handling 404 Not Found

HTTP 404 indicates that the requested resource could not be found.

if (response.status === 404) {

    Alert.alert(
        "Not Found",
        "The requested data was not found."
    );

    return;
}

11. Handling 422 Validation Error

HTTP 422 is commonly used when the request format is understandable but the submitted data fails validation.

if (response.status === 422) {

    const result =
        await response.json();

    console.log(
        result.errors
    );

    return;
}

12. Handling 500 Server Error

HTTP 500 indicates a server-side problem.

if (response.status === 500) {

    Alert.alert(
        "Server Error",
        "Something went wrong on the server."
    );

    return;
}

Detailed server errors should normally be logged on the server rather than exposed to the mobile user.

13. API Error JSON Response

A PHP REST API can return structured JSON when an error occurs.

{
    "success": false,
    "message": "Student not found"
}

React Native can read the message and display it to the user.

14. Validation Error Response

{
    "success": false,
    "message": "Validation failed",
    "errors": {
        "name": "Name is required",
        "email": "Invalid email"
    }
}

The errors object can contain field-specific validation messages.

15. Using try/catch

try/catch can handle errors such as network failures or exceptions thrown by your own code.

try {

    const response = await fetch(
        API_URL
    );

    console.log(response);

} catch (error) {

    console.log(
        error.message
    );

}

16. Network Error

If the device cannot reach the server, Fetch may reject the promise and the catch block can handle the error.

try {

    const response =
        await fetch(API_URL);

} catch (error) {

    Alert.alert(
        "Network Error",
        "Please check your internet connection."
    );

}

17. Combining Status and try/catch

try {

    const response = await fetch(
        API_URL
    );

    if (!response.ok) {

        throw new Error(
            `HTTP ${response.status}`
        );

    }

    const result =
        await response.json();

    console.log(result);

} catch (error) {

    console.log(
        error.message
    );

}

18. Reading the Error Message

const result =
    await response.json();

if (!response.ok) {

    throw new Error(
        result.message ||
        "API request failed"
    );
}

The API's message can provide a more useful explanation than a generic error message.

19. Reusable API Error Function

async function handleResponse(
    response
) {

    const result =
        await response.json();

    if (!response.ok) {

        throw new Error(
            result.message ||
            "API request failed"
        );
    }

    return result;
}

20. Error Handling with Loading State

async function loadStudents() {

    setLoading(true);
    setError("");

    try {

        const response =
            await fetch(API_URL);

        if (!response.ok) {

            const result =
                await response.json();

            throw new Error(
                result.message ||
                "Request failed"
            );
        }

        const result =
            await response.json();

        setStudents(
            result.data || []
        );

    } catch (error) {

        setError(
            error.message
        );

    } finally {

        setLoading(false);

    }
}

21. Displaying an Error in the UI

{error !== "" && (
    <View>

        <Text>
            {error}
        </Text>

    </View>
)}

A clear message helps users understand what they should do next.

22. Retry After an Error

A retry button can call the same API function again.

<Button
    title="Try Again"
    onPress={loadStudents}
/>

Retry functionality is especially useful for temporary network problems.

23. Authentication Error Flow

API Request
     ↓
HTTP 401
     ↓
Token Invalid / Expired
     ↓
Clear Local Session
     ↓
Go to Login Screen

The exact authentication flow depends on how the application's token system is designed.

24. Do Not Show Sensitive Server Errors

The PHP API should avoid returning sensitive technical details such as database credentials, SQL queries, secret keys, or stack traces.

A safer response is:

{
    "success": false,
    "message": "Something went wrong"
}

Detailed information can be written to server logs for debugging.

25. Error Handling with POST

async function addStudent() {

    try {

        const response =
            await fetch(API_URL, {

                method: "POST",

                headers: {
                    "Content-Type":
                        "application/json"
                },

                body: JSON.stringify({
                    name,
                    email
                })
            });

        const result =
            await response.json();

        if (!response.ok) {

            throw new Error(
                result.message ||
                "Unable to add student"
            );
        }

        Alert.alert(
            "Success",
            result.message
        );

    } catch (error) {

        Alert.alert(
            "Error",
            error.message
        );
    }
}

26. Error Handling with DELETE

async function deleteStudent(id) {

    try {

        const response =
            await fetch(
                `${API_URL}?id=${id}`,
                {
                    method: "DELETE"
                }
            );

        const result =
            await response.json();

        if (!response.ok) {

            throw new Error(
                result.message ||
                "Delete failed"
            );
        }

        Alert.alert(
            "Success",
            result.message
        );

    } catch (error) {

        Alert.alert(
            "Error",
            error.message
        );
    }
}

27. Centralized API Error Handling

Larger React Native applications should avoid repeating the same error handling code in every screen.

async function apiRequest(
    url,
    options = {}
) {

    try {

        const response =
            await fetch(url, options);

        const result =
            await response.json();

        if (!response.ok) {

            throw new Error(
                result.message ||
                "API request failed"
            );
        }

        return result;

    } catch (error) {

        throw error;

    }
}

28. Complete API Error Handling Example

const API_URL =
    "https://example.com/api/students.php";

async function loadStudents() {

    setLoading(true);
    setError("");

    try {

        const response =
            await fetch(API_URL);

        let result;

        try {

            result =
                await response.json();

        } catch (jsonError) {

            throw new Error(
                "Invalid server response"
            );

        }

        if (!response.ok) {

            if (response.status === 401) {

                throw new Error(
                    "Please login again."
                );

            }

            if (response.status === 403) {

                throw new Error(
                    "You do not have permission."
                );

            }

            if (response.status === 404) {

                throw new Error(
                    "Data was not found."
                );

            }

            if (response.status === 422) {

                throw new Error(
                    result.message ||
                    "Validation failed."
                );

            }

            if (response.status >= 500) {

                throw new Error(
                    "Server error. Please try again later."
                );

            }

            throw new Error(
                result.message ||
                "API request failed"
            );
        }

        if (!result.success) {

            throw new Error(
                result.message ||
                "Unable to load data"
            );

        }

        setStudents(
            result.data || []
        );

    } catch (error) {

        setError(
            error.message ||
            "Network error"
        );

    } finally {

        setLoading(false);

    }
}

29. Common API Error Handling Mistakes

  • Only checking whether fetch() completed.
  • Not checking response.ok.
  • Ignoring HTTP status codes.
  • Not using try/catch for network failures.
  • Trying to parse JSON when the response has no body.
  • Showing technical server errors to users.
  • Not handling 401 and 403 separately.
  • Not handling validation errors.
  • Not providing a retry option.
  • Not resetting loading after an error.
  • Not logging useful debugging information safely.

30. Complete API Error Handling Flow

React Native
      ↓
  Fetch Request
      ↓
   API Server
      ↓
  HTTP Response
      ↓
 ┌──────┴─────────┐
 ↓                ↓
Success          Error
 ↓                ↓
200/201       Check Status
 ↓                ↓
Show Data     400/401/403
              404/422/500
                   ↓
            Read JSON Error
                   ↓
             Show Message
                   ↓
             Retry / Login
                   ↓
              Update UI

Proper error handling makes a React Native REST API application more reliable, secure, and user-friendly.

📌 Key Points

  • API requests can fail for many different reasons.
  • Use response.ok and response.status to inspect HTTP responses.
  • Use try/catch to handle network and JavaScript errors.
  • Handle 400, 401, 403, 404, 422, and 500 appropriately.
  • Use structured JSON error responses from the PHP API.
  • Do not expose sensitive server or database information to users.
  • Use loading and error states together.
  • Provide retry functionality for temporary failures.
  • Handle authentication failures separately.
  • Use centralized error handling in larger applications.
  • Always give the user a clear and useful message.

🧠 Quick Quiz

Question: Which HTTP status code commonly indicates that a user is not authenticated?