Topic 8: HTTP
📖 7 min read · 🎯 intermediate · 🧭 Prerequisites: basics-stylescomponents-text-inputs-buttons-scrollview-activity-indicator-images-modals, basics-picker-status-bar-async-storage
Why this matters
Up until now, every app we've built has been a closed box — all the data lives inside the app itself. But think about every real app you use: WhatsApp fetches your messages, Swiggy pulls the latest menu, Cricbuzz loads live scores. None of that data lives on your phone. It comes from a server, over the internet, every time you open the app. That's HTTP — and today we're going to wire our React Native app to do exactly that, using Axios to send GET requests that fetch data and POST requests that send data out.
What You'll Learn
- Install and configure Axios, the promise-based HTTP client for JavaScript
- Create a service file that centralises API requests using
async/await - Fetch data from a REST API and render it with
FlatList - Send data to a REST API using
axios.postand display the server response
The Analogy
Think of Axios as a courier service operating out of your app. When you want information from a remote server, you hand Axios a addressed envelope (the URL and any parameters), and it rides out, knocks on the server's door, waits for a reply, and brings the package back to your component. If the server is unavailable or the address is wrong, the courier returns an error note instead of an empty-handed shrug — which is why Axios wraps every trip in a promise you can await and a catch block you can rely on.
Chapter 1: Setting Up Axios
Axios is a promise-based HTTP client for JavaScript. It simplifies sending asynchronous HTTP requests to REST endpoints and performing CRUD operations compared to the raw fetch API — it automatically parses JSON responses, handles request/response interceptors, and produces descriptive error objects.
Install Axios by running:
npm install axios
Once installed, import it anywhere in your project:
import axios from 'axios';
That single import gives you axios.get, axios.post, axios.put, axios.patch, and axios.delete — one method per HTTP verb.
Chapter 2: Fetching Data from an API
The class's first goal: pull posts from a public REST API and render them in a scrollable list.
Step 1 — Create a Service File
Centralising API calls in a dedicated service file keeps your components clean and makes it trivial to swap endpoints later.
api.js:
import axios from 'axios';
const API_URL = 'https://jsonplaceholder.typicode.com';
export const fetchPosts = async () => {
try {
const response = await axios.get(`${API_URL}/posts`);
return response.data;
} catch (error) {
console.error('Error fetching posts:', error);
throw error;
}
};
response.data is where Axios places the parsed JSON body — you never need to call .json() manually the way you would with fetch.
Step 2 — Create a Component to Display Data
PostsComponent.js:
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import { fetchPosts } from './api';
const PostsComponent = () => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const getPosts = async () => {
try {
const postsData = await fetchPosts();
setPosts(postsData);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
};
getPosts();
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
if (error) {
return <Text>Error: {error.message}</Text>;
}
return (
<FlatList
data={posts}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.post}>
<Text style={styles.title}>{item.title}</Text>
<Text>{item.body}</Text>
</View>
)}
/>
);
};
const styles = StyleSheet.create({
post: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
title: {
fontSize: 18,
fontWeight: 'bold',
},
});
export default PostsComponent;
Key patterns here:
- Three state slices —
posts,loading,error— cover every possible UI state. - The
useEffectwith an empty dependency array[]fires once on mount, triggering the fetch. keyExtractorconvertsitem.id(a number) to a string because React Native'sFlatListrequires string keys.
Step 3 — Integrate the Component in App
App.js:
import React from 'react';
import { StyleSheet, ScrollView, View } from 'react-native';
import PostsComponent from './PostsComponent';
export default function App() {
return (
<ScrollView contentContainerStyle={styles.container}>
<PostsComponent />
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 16,
},
});
sequenceDiagram
participant App
participant PostsComponent
participant api.js
participant JSONPlaceholder
App->>PostsComponent: renders
PostsComponent->>api.js: fetchPosts()
api.js->>JSONPlaceholder: GET /posts
JSONPlaceholder-->>api.js: 200 OK, JSON array
api.js-->>PostsComponent: response.data
PostsComponent->>PostsComponent: setPosts(), setLoading(false)
PostsComponent-->>App: renders FlatList
Chapter 3: Sending Data to an API
Reading data is only half the story. The class also needs to create new posts — which means sending a POST request with a JSON body.
Step 1 — Update the Service File
Add a createPost export alongside fetchPosts.
api.js (full file):
import axios from 'axios';
const API_URL = 'https://jsonplaceholder.typicode.com';
export const fetchPosts = async () => {
try {
const response = await axios.get(`${API_URL}/posts`);
return response.data;
} catch (error) {
console.error('Error fetching posts:', error);
throw error;
}
};
export const createPost = async (postData) => {
try {
const response = await axios.post(`${API_URL}/posts`, postData);
return response.data;
} catch (error) {
console.error('Error creating post:', error);
throw error;
}
};
axios.post takes the URL as the first argument and the request body as the second. Axios automatically serialises the object to JSON and sets the Content-Type: application/json header.
Step 2 — Create a Component to Send Data
CreatePostComponent.js:
import React, { useState } from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
import { createPost } from './api';
const CreatePostComponent = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [response, setResponse] = useState(null);
const handleCreatePost = async () => {
const postData = { title, body };
try {
const postResponse = await createPost(postData);
setResponse(postResponse);
} catch (error) {
console.error('Error creating post:', error);
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Title"
value={title}
onChangeText={setTitle}
/>
<TextInput
style={styles.input}
placeholder="Body"
value={body}
onChangeText={setBody}
/>
<Button title="Create Post" onPress={handleCreatePost} />
{response && (
<View style={styles.response}>
<Text>Post Created:</Text>
<Text>ID: {response.id}</Text>
<Text>Title: {response.title}</Text>
<Text>Body: {response.body}</Text>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
backgroundColor: '#fff',
borderRadius: 8,
marginVertical: 16,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 12,
paddingHorizontal: 8,
},
response: {
marginTop: 16,
},
});
export default CreatePostComponent;
The response state is null until a successful POST returns — the conditional {response && ...} block then renders the server-echoed fields (id, title, body). JSONPlaceholder always returns a fake id: 101 for new posts, confirming the round-trip worked.
Step 3 — Integrate Both Components in App
App.js (final version):
import React from 'react';
import { StyleSheet, ScrollView, View } from 'react-native';
import PostsComponent from './PostsComponent';
import CreatePostComponent from './CreatePostComponent';
export default function App() {
return (
<ScrollView contentContainerStyle={styles.container}>
<CreatePostComponent />
<PostsComponent />
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 16,
},
});
CreatePostComponent sits above PostsComponent so the form appears at the top, and the fetched list scrolls below it.
🧪 Try It Yourself
Task: Add a deletePost function to api.js that calls axios.delete, then build a DeletePostComponent with a numeric TextInput for the post ID and a "Delete Post" button. On success, display the message "Post [ID] deleted successfully."
Success criterion: Pressing the button with a valid post ID (e.g., 1) should log no errors to the console and render the success message beneath the button. JSONPlaceholder returns an empty {} body with status 200 for DELETE — treat a non-null response as success.
Starter snippet:
// api.js — add below createPost
export const deletePost = async (postId) => {
try {
const response = await axios.delete(`${API_URL}/posts/${postId}`);
return response.data;
} catch (error) {
console.error('Error deleting post:', error);
throw error;
}
};
🔍 Checkpoint Quiz
Q1. Why does axios.get not require a .json() call on the response, unlike the native fetch API?
A) Axios only works with JSON APIs and throws otherwise
B) Axios automatically parses the JSON response body and places it on response.data
C) React Native patches fetch to auto-parse JSON
D) The jsonplaceholder.typicode.com API sends pre-parsed objects
Q2. Given this snippet, what is logged to the console if the network request fails?
export const fetchPosts = async () => {
try {
const response = await axios.get(`${API_URL}/posts`);
return response.data;
} catch (error) {
console.error('Error fetching posts:', error);
throw error;
}
};
A) Nothing — errors are silently swallowed
B) 'Error fetching posts:' followed by the error object, then the error is re-thrown to the caller
C) 'Error fetching posts:' followed by the error object; execution continues normally
D) The component automatically shows a fallback UI
Q3. What is the purpose of the empty dependency array [] passed to useEffect in PostsComponent?
A) It disables the effect entirely B) It causes the effect to re-run every time any state changes C) It causes the effect to run once after the initial render and never again D) It passes an empty posts array as initial data
Q4. You want to update a post's title without replacing the whole document. Which Axios method and endpoint pattern should you use?
A) axios.post('/posts/1', { title: 'New title' })
B) axios.put('/posts/1', { title: 'New title' }) — replaces the full resource
C) axios.patch('/posts/1', { title: 'New title' }) — partial update, only sends changed fields
D) axios.get('/posts/1/update?title=New+title')
A1. B — Axios parses JSON automatically and exposes the result on response.data, removing the need for a second .json() await step.
A2. B — The catch block logs the error with console.error, then throw error re-throws it so the calling component's own catch block can also handle it (e.g., set error state).
A3. C — An empty [] dependency array tells React to run the effect only after the first render (equivalent to componentDidMount). Without it, the effect would re-run after every state change, causing an infinite fetch loop.
A4. C — axios.patch is the correct choice for partial updates. axios.put replaces the entire resource, which would wipe fields you didn't include in the request body.
🪞 Recap
- Install Axios with
npm install axios; import it withimport axios from 'axios'. - Centralise API calls in a service file (e.g.,
api.js) usingasync/awaitand try/catch for clean error handling. axios.get(url)fetches data; the parsed JSON body lives onresponse.data.axios.post(url, body)sends data; Axios serialises the object to JSON and sets the correctContent-Typeheader automatically.- Manage three state slices —
data,loading,error— in components that fetch, so every UI state is handled.
📚 Further Reading
- Axios GitHub repository — the source of truth on config options, interceptors, and cancellation
- JSONPlaceholder — the free fake REST API used in every example here; great for prototyping
- React Native Networking docs — official guide covering
fetch, WebSockets, and security considerations - ⬅️ Previous: Picker, Status Bar, Async Storage
- ➡️ Next: Navigation