Working with Network and API
1. Using Fetch API
| Property | Description | Example |
|---|---|---|
| fetch() | Method to make HTTP requests | fetch('https://api.example.com/data') |
| method | HTTP method (GET, POST, PUT, DELETE) | { method: 'POST' } |
| headers | Request headers to send | { 'Content-Type': 'application/json' } |
| body | Request body (for POST/PUT) | JSON.stringify({ name: 'John' }) |
Example: Fetch GET request
const response = await fetch('https://api.example.com/users');
const data = await response.json();
console.log(data);
Example: Fetch POST request
const newUser = {
name: 'Jane Doe',
email: 'jane@example.com'
};
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUser)
});
const result = await response.json();
console.log(result);
Note: In Expo,
fetch is supported natively and works the same as in web browsers.
2. Making GET Requests
Example: Fetching Data from an API
import { useState, useEffect } from 'react';
import { fetch } from 'expo';
export default function UserProfile() {
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/user/123')
.then(response => response.json())
.then(data => {
setUserData(data);
setLoading(false);
})
.catch(error => {
console.error('Error fetching user data:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return <div>Hello, {userData.name}!</div>;
}
| Property | Description | Default |
|---|---|---|
| url | The URL to make the GET request to | Required |
| headers | Object containing headers to send with the request | None |
| method | The HTTP method (GET, POST, etc.) | GET |
Note: When using
fetch in Expo, ensure that the API endpoint supports CORS if making requests to external domains.
Warning: Always handle potential errors in your GET requests to prevent unhandled promise rejections.
3. Making POST Requests
| Property | Description | Example |
|---|---|---|
| url | The endpoint to send the POST request to | https://api.example.com/users |
| body | Data to be sent in the request body | { name: "John", age: 30 } |
| headers | Optional headers to include in the request | { "Content-Type": "application/json" } |
Example: Sending a POST Request with Expo
import { fetch } from "expo";
const postData = {
name: "John",
age: 30
};
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(postData)
});
console.log("Response:", response);
4. Sending Request Headers
| Header | Description | Usage |
|---|---|---|
| Authorization | Used for authentication with a server | headers: { Authorization: 'Bearer token123' } |
| Content-Type | Indicates the media type of the resource | headers: { 'Content-Type': 'application/json' } |
| Accept | Specifies the media types that are acceptable for the response | headers: { Accept: 'application/json' } |
| User-Agent | Identifies the client making the request | headers: { 'User-Agent': 'Expo App v1.0' } |
Example: Sending Custom Headers with Fetch
fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'Authorization': 'Bearer <token>',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data));
5. Handling JSON Response
| Method | Description | Return Type | Example |
|---|---|---|---|
| fetch() | Standard browser API to make HTTP requests | Promise<Response> | const response = await fetch('https://api.example.com/data');<br>const data = await response.json(); |
| axios.get() | Popular HTTP client for making GET requests | Promise<AxiosResponse> | const response = await axios.get('https://api.example.com/data');<br>const data = response.data; |
| expo-constants | Access app constants including API endpoints | Object | import Constants from 'expo-constants';<br>const apiUrl = Constants.expoConfig.extra.apiUrl; |
Note: When using
fetch, always handle potential errors and check the response status before parsing JSON.Warning: Never hardcode API keys or sensitive data in client-side code. Use environment variables or secure backend services.
6. Using Axios Library
| Feature | Description | Notes |
|---|---|---|
| Installation | npm install axios |
Available via npm or yarn |
| Basic GET Request | |
Promise-based HTTP client |
| Request Config | |
Supports query params and headers |
Example: Fetching Data with Axios
import axios from 'axios';
const fetchData = async () => {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
console.log(response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
Example: POST Request with Data
import axios from 'axios';
const postData = async () => {
try {
const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
title: 'My New Post',
body: 'This is the content of my post.',
userId: 1
});
console.log('Created:', response.data);
} catch (error) {
console.error('Error posting data:', error);
}
};
postData();
Note: Axios provides automatic JSON parsing and supports interceptors for request/response handling.
Warning: Ensure proper error handling when making network requests in mobile environments.
7. Implementing Interceptors
| Interceptor Type | Description | Usage |
|---|---|---|
| Request Interceptor | Modifies outgoing requests before they are sent | axios.interceptors.request.use(config => { ... }) |
| Response Interceptor | Modifies incoming responses before they are handled | axios.interceptors.response.use(response => { ... }) |
Example: Request Interceptor
import axios from 'axios';
const instance = axios.create({
baseURL: 'https://api.example.com'
});
instance.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
Example: Response Interceptor
instance.interceptors.response.use(
(response) => {
console.log('Response received:', response);
return response;
},
(error) => {
if (error.response?.status === 401) {
// Redirect to login or refresh token
console.log('Unauthorized, redirecting...');
}
return Promise.reject(error);
}
);
Note: Interceptors in Expo apps should be used carefully to avoid performance issues or infinite loops.
8. Handling Network Errors
| Error Type | Description | Handling Strategy | Example |
|---|---|---|---|
| TypeError | Occurs when network request fails due to invalid URL or missing network | Use try/catch and check for valid URL before making request | |
| NetworkError | Indicates a failure in the network layer (e.g., timeout, DNS issues) | Implement retry logic with exponential backoff | Example: Retry Logic |
| TimeoutError | Request exceeds configured timeout threshold | Set timeout limits and handle timeout gracefully | |
Note: Always implement error boundaries in your app to gracefully handle network failures and provide user feedback.
Best Practices for Network Error Handling
- Use
try/catchblocks around network calls - Implement retry logic for transient errors
- Set timeouts to prevent hanging requests
- Provide user-friendly error messages
9. Detecting Network State
Example: Check network status
import { Network } from 'expo-network';
export default function NetworkStatus() {
const [networkState, setNetworkState] = useState(null);
useEffect(() => {
const checkNetwork = async () => {
const state = await Network.getNetworkStateAsync();
setNetworkState(state);
};
checkNetwork();
}, []);
return (
<View style={styles.container}>
<Text>Network Type: {networkState?.type || 'Unknown'}</Text>
<Text>Is Connected: {networkState?.isConnected ? 'Yes' : 'No'}</Text>
</View>
);
}
| Property | Description | Values |
|---|---|---|
| type | Network type detected | "UNKNOWN", "ETHERNET", "WIFI", "CELLULAR", "NONE" |
| isConnected | Whether device has network access | true, false |
| isInternetReachable | Whether device can reach the internet | true, false, null (unknown) |
Note: On Android,
isInternetReachable may return null if the device is connected to a network that does not have internet access.
Warning: Network state can change dynamically. It's recommended to listen for changes using
Network.addEventListener.
Example: Listen for network changes
import { Network } from 'expo-network';
const handleNetworkChange = (networkState) => {
console.log("Network changed:", networkState);
};
Network.addEventListener("networkStateChange", handleNetworkChange);
// Don't forget to remove listener when component unmounts
useEffect(() => {
return () => {
Network.removeEventListener("networkStateChange", handleNetworkChange);
};
}, []);
10. Using WebSockets
| Property | Description | Example |
|---|---|---|
| WebSocket URL | URL to connect to the WebSocket server | wss://example.com/websocket |
| Connection Status | Indicates the state of the WebSocket connection | OPEN, CLOSING, CLOSED |
Example: Establishing a WebSocket Connection
import * as WebSocket from 'ws';
const ws = new WebSocket("wss://example.com/websocket");
ws.on("open", () => {
console.log("Connected to WebSocket server");
});
ws.on("message", (data) => {
console.log("Received:", data);
});
ws.on("close", () => {
console.log("WebSocket connection closed");
});
Example: Sending Data via WebSocket
const message = {
type: "chat",
content: "Hello, server!"
};
ws.send(JSON.stringify(message));
Note: Ensure that your server supports WebSocket connections and that the URL uses
wss:// for secure connections.
Warning: WebSocket connections may not work in all environments (e.g., some web browsers or network configurations). Always test in your target environment.
11. Implementing GraphQL
Example: Setting up a GraphQL client with Apollo
import { ApolloClient, InMemoryCache, ApolloProvider, useQuery } from '@apollo/client';
import { gql } from 'graphql-tag';
const client = new ApolloClient({
uri: 'https://your-graphql-endpoint.com/graphql',
cache: new InMemoryCache()
});
const GET_POSTS = gql`
query GetPosts {
posts {
id
title
content
}
}
`;
function PostsList() {
const { loading, error, data } = useQuery(GET_POSTS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
| Feature | Description | Notes |
|---|---|---|
| Apollo Client | @apollo/client |
Popular GraphQL client for React and React Native |
| GraphQL Schema | gql |
Used to define queries and mutations in JavaScript |
| Server Integration | Expo supports GraphQL via HTTP clients | Use fetch or axios for direct API calls |
Note: Expo does not include built-in GraphQL support, but it works well with Apollo Client and other GraphQL libraries.
12. Caching API Requests
| Property | Description | Default |
|---|---|---|
| cacheTTL | Time-to-live for cached responses in milliseconds | 300000 |
| cacheKey | Custom key to identify the cache entry | null |
| enableCache | Enable or disable caching for the request | true |
Example: Using cacheTTL
import { cache } from 'expo-api';\n\nconst response = await cache.fetch('https://api.example.com/data', {\n cacheTTL: 60000,\n method: 'GET'\n});
Note: Caching is particularly useful for API endpoints that return static or semi-static data, such as user profiles or configuration files.