React Native Axios API Layer
Small apps call fetch directly inside screens. Growing apps repeat the same address, headers, and error handling in dozens of places. An API layer gathers all server communication into one organized module. Axios, a popular HTTP library, makes that module short, readable, and easy to maintain.
Why Build a Layer
Without a layer With a layer ─────────────────── ────────────────────────── Screen → server Screen → api/products.js → client → server Screen → server Screen → api/users.js → client → server Screen → server One place for URL, token, errors Repeated code everywhere
Install Axios
npm install axios
Step 1: Create a Shared Client
An Axios instance stores the base address, timeout, and default headers. Every request inherits them.
// src/api/client.js
import axios from 'axios';
const client = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 10000,
headers: { 'Content-Type': 'application/json' },
});
export default client;
Step 2: Write Endpoint Functions
Group related calls into files. Screens call a named function and never see URLs.
// src/api/products.js
import client from './client';
export const getProducts = async (page = 1) => {
const { data } = await client.get('/products', { params: { page } });
return data;
};
export const getProduct = async (id) => {
const { data } = await client.get(`/products/${id}`);
return data;
};
export const createProduct = async (product) => {
const { data } = await client.post('/products', product);
return data;
};
export const deleteProduct = (id) => client.delete(`/products/${id}`);
Axios turns the params object into a query string and converts JSON automatically, which removes manual parsing work.
Step 3: Attach the Token Automatically
A request interceptor runs before every call. Use it to add the sign-in token once.
import * as SecureStore from 'expo-secure-store';
client.interceptors.request.use(async (config) => {
const token = await SecureStore.getItemAsync('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
Screen calls getProducts()
│
▼
Request interceptor adds token
│
▼
Server
│
▼
Response interceptor checks errors
│
▼
Screen receives data
Step 4: Handle Errors in One Place
A response interceptor catches failures from every call. Translate technical errors into friendly messages.
client.interceptors.response.use(
(response) => response,
(error) => {
if (!error.response) {
return Promise.reject(new Error('No internet connection'));
}
if (error.response.status === 401) {
signOutUser();
}
if (error.response.status >= 500) {
return Promise.reject(new Error('Server problem. Try again soon.'));
}
return Promise.reject(error);
}
);
Step 5: Use the Layer in a Screen
function ProductScreen() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
const load = async () => {
try {
setProducts(await getProducts());
} catch (e) {
setError(e.message);
} finally {
setLoading(false);
}
};
load();
}, []);
if (loading) return <ActivityIndicator />;
if (error) return <Text>{error}</Text>;
return <FlatList data={products} renderItem={renderProduct} />;
}
Cancel Requests
A user may leave a screen before a request ends. An abort controller cancels the call and avoids updates on a closed screen.
useEffect(() => {
const controller = new AbortController();
client.get('/products', { signal: controller.signal });
return () => controller.abort();
}, []);
Environment Addresses
Keep the base address in an environment variable so development and production point to different servers without code changes.
Axios or Fetch?
Feature fetch Axios ────────────────────────────────────────── Built in Yes No (install) Auto JSON parsing Manual Automatic Interceptors No Yes Timeout setting Manual Built in Error on 4xx / 5xx No Yes
Summary
An API layer centralizes server communication. Create one Axios client with a base address and timeout, write endpoint functions per feature, attach tokens with a request interceptor, and translate failures with a response interceptor. Screens then stay clean and call simple named functions.
