Using Axios With React Native to Manage API Requests

Master HTTP client implementation with Axios in React Native. From basic setup to advanced interceptor patterns for production-ready API management.

Modern React Native applications rarely work in isolation. Most require communication with REST APIs to fetch data, submit forms, authenticate users, and synchronize state with backend servers. While React Native provides the native Fetch API, Axios has emerged as the preferred choice for production applications due to its cleaner syntax, robust error handling, and powerful interceptor system.

This comprehensive guide explores how to effectively manage API requests using Axios in React Native applications, covering everything from basic configuration to advanced patterns that scale across large applications.

Whether you're building a mobile app for your business or integrating third-party services, proper API management is foundational to a reliable user experience.

Why Choose Axios for React Native

Key advantages that make Axios the preferred HTTP client for production React Native applications

Clean, Intuitive API

Axios provides a straightforward interface for all HTTP methods with consistent patterns across GET, POST, PUT, and DELETE requests.

Powerful Interceptors

Intercept requests and responses to add authentication tokens, transform data, or handle errors globally across your application.

Automatic JSON Handling

Axios automatically transforms JSON data, eliminating the need for manual response.json() calls required with the Fetch API.

Built-in Error Handling

Receive consistent error objects with detailed information about network failures, HTTP status codes, and response data.

Request Cancellation

Easily cancel pending requests when components unmount, preventing memory leaks and unnecessary network traffic.

TypeScript-First Design

Excellent TypeScript support with comprehensive type definitions for requests, responses, and error handling.

Installing and Configuring Axios in React Native

Getting started with Axios in your React Native project is straightforward. The library requires no native linking for React Native 0.60 and above, making installation a simple package manager command.

Installation

npm install axios
# or
yarn add axios

No additional configuration is required for basic usage. Axios works out of the box with React Native's JavaScript runtime and integrates seamlessly with the networking layer.

Creating a Centralized Axios Instance

For production applications, creating a centralized Axios instance is essential for maintainability. This pattern ensures consistent configuration across all API calls and makes future changes easier to implement. When working with a full-stack development team, this centralized approach enables easier testing and debugging.

import axios from 'axios';

const api = axios.create({
 baseURL: 'https://api.yourdomain.com',
 timeout: 10000,
 headers: {
 'Content-Type': 'application/json',
 'Accept': 'application/json',
 },
});

Key configuration options include:

  • baseURL: Centralizes your API endpoint, eliminating repeated URL strings
  • timeout: Prevents requests from hanging indefinitely on network issues
  • headers: Sets default headers applied to every request
Centralized Axios Instance Configuration
1import axios from 'axios';2 3// Create a centralized API instance with production-ready configuration4const apiClient = axios.create({5 baseURL: process.env.EXPO_PUBLIC_API_URL || 'https://api.example.com',6 timeout: 15000, // 15 seconds timeout for better UX7 headers: {8 'Content-Type': 'application/json',9 'Accept': 'application/json',10 },11});12 13// Export for use throughout the application14export default apiClient;

Making HTTP Requests With Axios

Axios provides intuitive methods for all standard HTTP operations. Each method returns a Promise, making it compatible with modern async/await syntax and React Native's component lifecycle.

GET Requests - Fetching Data

GET requests retrieve data from your API. In React Native, you'll typically call these within useEffect hooks or event handlers, managing loading and error states for a smooth user experience. This pattern integrates well with modern state management approaches in React Native applications.

const fetchUserPosts = async (userId) => {
 try {
 const response = await apiClient.get(`/users/${userId}/posts`);
 return response.data;
 } catch (error) {
 console.error('Failed to fetch posts:', error);
 throw error;
 }
};

POST Requests - Creating Resources

POST requests send data to create new resources. Include the data in the second argument, and Axios handles serialization automatically.

const createPost = async (postData) => {
 try {
 const response = await apiClient.post('/posts', postData);
 return response.data;
 } catch (error) {
 console.error('Failed to create post:', error);
 throw error;
 }
};

PUT and PATCH Requests - Updating Resources

Use PUT for complete resource replacements and PATCH for partial updates. Both follow similar patterns with the resource ID and update data.

// Complete update with PUT
const updatePost = async (postId, updatedData) => {
 const response = await apiClient.put(`/posts/${postId}`, updatedData);
 return response.data;
};

// Partial update with PATCH
const patchPost = async (postId, partialData) => {
 const response = await apiClient.patch(`/posts/${postId}`, partialData);
 return response.data;
};

DELETE Requests - Removing Resources

DELETE requests remove resources by ID. They typically return an empty response on success.

const deletePost = async (postId) => {
 await apiClient.delete(`/posts/${postId}`);
 return true;
};

For applications requiring real-time data synchronization, consider integrating WebSocket communication alongside traditional REST endpoints. Additionally, if you're comparing charting libraries for data visualization, explore our guide on JavaScript charting libraries that work seamlessly with Axios data fetching.

Leveraging Axios Interceptors

Interceptors are one of Axios's most powerful features, allowing you to run code before requests are sent and before responses are returned. This enables centralized handling of authentication, logging, error transformation, and more.

Request Interceptors

Request interceptors execute before each HTTP request is sent, making them ideal for adding authentication tokens, logging request details, or transforming request data. This pattern is essential for maintaining secure communication in production mobile applications.

import AsyncStorage from '@react-native-async-storage/async-storage';

apiClient.interceptors.request.use(
 async (config) => {
 // Retrieve stored authentication token
 const token = await AsyncStorage.getItem('authToken');
 
 // Attach token to authorization header if available
 if (token) {
 config.headers.Authorization = `Bearer ${token}`;
 }
 
 // Log request for debugging (avoid in production)
 console.log(`[API] ${config.method?.toUpperCase()} ${config.url}`);
 
 return config;
 },
 (error) => {
 // Handle request configuration errors
 return Promise.reject(error);
 }
);

Response Interceptors

Response interceptors process API responses before they're returned to your application code. Use them for global error handling, token refresh on 401 errors, and response transformation.

apiClient.interceptors.response.use(
 (response) => {
 // Pass through successful responses
 return response;
 },
 async (error) => {
 const originalRequest = error.config;
 
 // Handle 401 Unauthorized - attempt token refresh
 if (error.response?.status === 401 && !originalRequest._retry) {
 originalRequest._retry = true;
 
 try {
 const refreshToken = await AsyncStorage.getItem('refreshToken');
 const response = await apiClient.post('/auth/refresh', { refreshToken });
 
 const { token } = response.data;
 await AsyncStorage.setItem('authToken', token);
 
 // Retry original request with new token
 originalRequest.headers.Authorization = `Bearer ${token}`;
 return apiClient(originalRequest);
 } catch (refreshError) {
 // Redirect to login on refresh failure
 await AsyncStorage.multiRemove(['authToken', 'refreshToken']);
 // Navigate to login screen
 return Promise.reject(refreshError);
 }
 }
 
 return Promise.reject(error);
 }
);

Implementing robust interceptor patterns is essential when building secure mobile applications that handle sensitive user data. For clean code organization, consider using path aliases in your React TypeScript imports.

Implementing Robust Error Handling

Production applications require comprehensive error handling that provides meaningful feedback to users while logging detailed information for debugging. Axios provides consistent error structures that make this achievable.

Understanding Axios Error Types

Axios errors fall into two categories that require different handling approaches:

  1. Network Errors: Occur when the request cannot be completed, such as DNS resolution failures, network connectivity issues, or timeout expiration. These errors have no response property.

  2. HTTP Errors: Occur when the server responds with an error status code (4xx or 5xx). These errors include response data with status, headers, and server-provided error messages.

Creating a Unified Error Handler

Centralize error handling logic to ensure consistent user feedback and logging across your application. This approach scales well for complex React Native projects with multiple API integrations.

const handleApiError = (error) => {
 if (axios.isAxiosError(error)) {
 if (error.response) {
 // Server responded with error status
 const { status, data } = error.response;
 
 switch (status) {
 case 400:
 return 'Invalid request. Please check your input.';
 case 401:
 return 'Session expired. Please log in again.';
 case 403:
 return 'You do not have permission to perform this action.';
 case 404:
 return 'The requested resource was not found.';
 case 500:
 return 'Server error. Please try again later.';
 default:
 return data.message || 'An unexpected error occurred.';
 }
 } else if (error.request) {
 // Request sent but no response received
 return 'Network error. Please check your connection.';
 }
 }
 
 return 'An unexpected error occurred. Please try again.';
};

Implementing Retry Logic

For transient failures, implement retry logic with exponential backoff to improve reliability without overwhelming servers. When handling edge cases like null and empty function parameters in JavaScript, robust error handling becomes even more critical.

const retryRequest = async (error) => {
 const config = error.config;
 
 // Only retry on network errors or 5xx status
 if (!error.response || error.response.status >= 500) {
 // Limit retry attempts
 if (!config._retryCount) {
 config._retryCount = 0;
 }
 
 if (config._retryCount < 3) {
 config._retryCount += 1;
 
 // Exponential backoff delay
 const delay = Math.pow(2, config._retryCount) * 1000;
 await new Promise(resolve => setTimeout(resolve, delay));
 
 return apiClient(config);
 }
 }
 
 return Promise.reject(error);
};

Managing Authentication and Security

Secure API communication is critical for mobile applications handling sensitive user data. Implement these patterns to protect your application and users.

Token Management Best Practices

Store authentication tokens securely using React Native's encrypted storage solutions. Never store tokens in plain text or AsyncStorage without encryption. For enterprise applications, consider integrating with your existing identity management systems.

import * as SecureStore from 'expo-secure-store';

const storeToken = async (key, value) => {
 await SecureStore.setItemAsync(key, value);
};

const getToken = async (key) => {
 return await SecureStore.getItemAsync(key);
};

const removeToken = async (key) => {
 await SecureStore.deleteItemAsync(key);
};

Security Checklist for React Native API Calls

  • Use HTTPS exclusively for all API communications
  • Implement certificate pinning for high-security applications
  • Validate all responses before processing data
  • Sanitize user inputs before including in requests
  • Implement proper logout that clears all stored credentials
  • Use interceptors for consistent auth token injection
  • Handle token expiration gracefully with refresh or redirect to login

Platform-Specific Security Considerations

iOS (ATS - App Transport Security):

iOS 9+ enforces ATS, requiring HTTPS connections by default. To allow cleartext development servers, update your Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
 <key>NSAllowsArbitraryLoads</key>
 <false/>
 <key>NSAllowsArbitraryLoadsForMedia</key>
 <false/>
 <key>NSAllowsArbitraryLoadsInWebContent</key>
 <false/>
</dict>

Android:

As of API Level 28, cleartext traffic is blocked by default. Enable only when necessary:

<application
 android:usesCleartextTraffic="false"
 ...>

For high-security mobile applications, explore our custom software development services that implement comprehensive security architectures.

Performance Optimization Strategies

Optimizing API performance improves both user experience and battery life. Implement these strategies to create responsive, efficient React Native applications.

Request Cancellation

Prevent memory leaks and wasted network traffic by canceling requests when components unmount. This is especially important in scrollable lists where users navigate quickly. Combining this with efficient state management patterns creates a responsive user experience.

import { useEffect, useRef } from 'react';

const useCancellableRequest = () => {
 const cancelSourceRef = useRef(axios.CancelToken.source());
 
 useEffect(() => {
 return () => {
 // Cancel pending request on component unmount
 cancelSourceRef.current.cancel('Component unmounted');
 };
 }, []);
 
 const makeRequest = async (requestFn) => {
 try {
 const response = await requestFn({
 cancelToken: cancelSourceRef.current.token,
 });
 return response.data;
 } catch (error) {
 if (axios.isCancel(error)) {
 console.log('Request canceled:', error.message);
 } else {
 throw error;
 }
 }
 };
 
 return { makeRequest };
};

Caching Strategies

Implement intelligent caching to reduce redundant network requests and improve perceived performance:

  • Cache successful GET responses with appropriate TTL (time-to-live)
  • Use React Query or SWR for built-in caching and background refetching
  • Implement stale-while-revalidate patterns for instant loads with background updates

Request Optimization Tips

  • Bundle multiple related data requests when possible
  • Use compression for large payloads
  • Request only necessary fields using API query parameters
  • Implement pagination for large data sets

Performance optimization is a critical consideration when developing scalable mobile applications that handle complex data operations. For offline data persistence, explore our guide on using SQLite in React Native.

Best Practices Summary

Key guidelines for production-ready Axios implementations in React Native

Centralize API Configuration

Create a single Axios instance with consistent base URL, timeouts, and default headers.

Use Interceptors Wisely

Implement request interceptors for auth and logging, response interceptors for error handling.

Handle All Error Cases

Differentiate between network errors, HTTP errors, and handle each appropriately.

Cancel Unused Requests

Prevent memory leaks by canceling pending requests when components unmount.

Secure Token Storage

Use encrypted storage for authentication tokens, never plain AsyncStorage.

Type Your API Layer

Use TypeScript interfaces for requests, responses, and errors throughout your API layer.

Conclusion

Implementing Axios for API management in React Native provides a robust foundation for building reliable, maintainable mobile applications. By centralizing configuration, leveraging interceptors for cross-cutting concerns, and implementing comprehensive error handling, you create an API layer that scales with your application.

The patterns covered in this guide--from basic request handling to advanced authentication and performance optimization--represent best practices that will serve your applications well as they grow in complexity. Remember that API integration is not a one-time implementation but an ongoing process of refinement based on user feedback and changing requirements.

Start with a centralized Axios instance and basic error handling, then progressively add interceptors, caching, and optimization as your application's needs evolve. This incremental approach ensures you build a solid foundation without over-engineering early in your project lifecycle.

For organizations looking to build enterprise-grade mobile applications, partnering with experienced mobile development professionals can accelerate delivery and ensure best practices are implemented from the start.

Frequently Asked Questions

Ready to Build Robust React Native Applications?

Our team of experienced developers can help you implement production-ready API integrations and build high-quality mobile applications.

Sources

  1. LogRocket: Using Axios with React Native to manage API requests - Comprehensive guide covering Axios installation, configuration, error handling, interceptors, and best practices for React Native API management

  2. DJamware: React Native REST API Integration with Axios and Context API - Detailed tutorial on integrating REST APIs with Axios and Context API, including TypeScript, CRUD operations, and production-ready architecture

  3. React Native Official Documentation: Networking - Official networking guidance covering Fetch API, XMLHttpRequest, WebSockets, and security considerations for mobile networking