Topic 49 of 56 · Full Stack Advanced

Topic 8 : HTTP

Lesson TL;DRTopic 8: HTTP 📖 7 min read · 🎯 intermediate · 🧭 Prerequisites: addingmiddleware, buildingahttpserverwithnodejsusinghttpapis Why this matters Up until now, every app you've built has been talking to...
7 min read·intermediate·http · axios · react-native · api

Topic 8: HTTP

📖 7 min read · 🎯 intermediate · 🧭 Prerequisites: adding-middleware, building-a-http-server-with-node-js-using-http-apis

Why this matters

Up until now, every app you've built has been talking to itself — the data is hardcoded, nothing moves, nothing changes unless you write it in. But real apps talk to the outside world. They fetch live data, send form submissions, pull in posts from a server somewhere. That conversation happens over HTTP, and Axios is the tool that makes it simple in React Native. Today we'll connect your app to a real REST API, fetch posts, create posts, and see exactly how that promise-based flow works — request goes out, response comes back, your app reacts.

What You'll Learn

  • Install and configure Axios in a React Native project
  • Fetch data from a public REST API and render it with FlatList
  • Send POST data to an API and display the server's response
  • Separate HTTP logic into a reusable service file (api.js)

The Analogy

Think of Axios as a courier service operating inside your app. When your component needs a package of data from a remote warehouse (the API server), it hands the courier a delivery note (the request URL and method) and goes about its business — no blocking, no waiting at the door. The courier runs the errand asynchronously, and when the package arrives it rings the doorbell (resolves the promise) and hands over the goods. If the warehouse is closed or the address is wrong, the courier files an error report instead of just disappearing. Axios is that reliable, promise-aware courier — it handles the round trip so your UI code never has to leave the building.

Chapter 1: Setting Up Axios

Axios is a promise-based HTTP client for JavaScript. It makes it straightforward to send asynchronous HTTP requests to REST endpoints and perform CRUD operations (Create, Read, Update, Delete) without reaching for the lower-level fetch API directly.

Step 1: Install Axios

npm install axios

Once installed, Axios is available anywhere in the project via a standard import:

import axios from 'axios';

Key characteristics worth knowing before writing any requests:

  • Returns a Promise for every request — compatible with async/await and .then()/.catch() chains
  • Automatically serializes request bodies to JSON and parses JSON responses
  • Throws an error for any HTTP status outside 2xx, so catch blocks receive real network or server errors
  • Supports request/response interceptors, making it easy to attach auth tokens or log traffic globally

Chapter 2: Fetching Data from an API

The class's first task was to retrieve a list of posts from the public jsonplaceholder.typicode.com API and display them in the mobile app.

Step 1: Create a Service File

Separating HTTP calls into a dedicated file keeps components clean and makes the API surface easy to swap 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;
  }
};

axios.get sends a GET request to the provided URL. The resolved value is a response object whose .data property holds the parsed JSON body.

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;

The component tracks three pieces of state: the array of posts, a loading boolean, and an error object. The useEffect with an empty dependency array fires once on mount, triggers the fetch, and flips loading to false regardless of success or failure. FlatList requires a keyExtractor so React can reconcile list items efficiently — item.id.toString() satisfies that requirement.

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,
  },
});

ScrollView with contentContainerStyle allows the list to grow past the screen height while keeping the layout centered.

Chapter 3: Sending Data to an API

Reading data is only half the picture. The class next learned to write data — creating a new post by sending a POST request with a JSON body.

Step 1: Update the Service File

Extend api.js with a createPost function alongside the existing fetchPosts.

api.js (updated):

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 accepts the URL as the first argument and the request body as the second. Axios serializes the JavaScript object to JSON automatically 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;

Two controlled TextInput fields bind to title and body state. Pressing the button calls handleCreatePost, which packages the state into postData and passes it to the service layer. When the server responds, the returned object (including its server-assigned id) is stored in response and rendered below the form.

Step 3: Integrate Both Components in App

App.js (final):

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 renders above PostsComponent so the form sits at the top of the scroll view and the list of fetched posts follows beneath it.

🧪 Try It Yourself

Task: Add a deletePost function to api.js and wire it to a Delete button on each rendered post in PostsComponent.

  1. In api.js, export a new async function:
export const deletePost = async (id) => {
  try {
    const response = await axios.delete(`${API_URL}/posts/${id}`);
    return response.status; // 200 on success
  } catch (error) {
    console.error('Error deleting post:', error);
    throw error;
  }
};
  1. In PostsComponent.js, import deletePost and add a Button inside renderItem:
import { deletePost } from './api';

// inside renderItem:
<Button title="Delete" onPress={() => deletePost(item.id).then(status => console.log('Status:', status))} />

Success criterion: Pressing Delete on any post logs Status: 200 in the console (JSONPlaceholder simulates the deletion without actually removing data).

🔍 Checkpoint Quiz

Q1. What does it mean that Axios is "promise-based"?

A) It caches every response automatically
B) Every HTTP call returns a Promise that resolves with the response or rejects on error
C) It only works inside async functions, not with .then()
D) It converts all responses to strings before returning them

Q2. Given this snippet, what is the value of result on a successful request?

const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
const result = response.data;

A) The raw HTTP response string
B) The parsed JavaScript object representing post #1
C) A Promise that must be awaited again
D) The HTTP status code (200)

Q3. The following useEffect has a bug. What is it?

useEffect(async () => {
  const data = await fetchPosts();
  setPosts(data);
});

A) fetchPosts is not a valid function name
B) The dependency array is missing, so the effect re-runs after every render
C) setPosts cannot accept an array
D) async functions cannot be used anywhere inside a component

Q4. How would you send a POST request with Axios that includes both a JSON body and a custom Authorization header?

A1. B — Axios wraps every HTTP call in a Promise, so you can use await or .then()/.catch() to handle the asynchronous result.

A2. B — response.data holds the body Axios has already parsed from JSON into a plain JavaScript object.

A3. B — The empty dependency array [] is missing. Without it, the effect fires after every render, causing an infinite fetch loop. Add [] as the second argument to run it only on mount.

A4. Pass a config object as the third argument to axios.post:

await axios.post(url, bodyData, {
  headers: { Authorization: `Bearer ${token}` },
});

🪞 Recap

  • Axios is installed via npm install axios and provides a promise-based interface for GET, POST, PUT, DELETE, and other HTTP verbs.
  • Separating requests into a service file (api.js) keeps components focused on rendering rather than data-fetching logistics.
  • axios.get(url) fetches data; axios.post(url, body) sends data — both resolve to a response object whose .data holds the parsed JSON.
  • In React Native components, useEffect with an empty dependency array is the standard pattern for triggering a one-time data fetch on mount.
  • Always handle both the loading and error states so users see feedback instead of a blank screen while the request is in flight.

📚 Further Reading

Like this topic? It’s one of 56 in Full Stack Advanced.

Block your seat for ₹2,500 and join the next cohort.