How to Use Mock APIs in React Applications

Step-by-step guide to integrating mock API endpoints into your React app using fetch and axios — so you can build UI components without waiting for a real backend.

How to Use Mock APIs in React Applications

React development and backend development rarely move at the same pace. If your UI work is blocked every time you need a new API endpoint, your team is losing days of productivity. Mock APIs break this dependency entirely.

In this guide, we'll walk through exactly how to wire up mock API endpoints in a React application — from a simple useEffect fetch to a proper environment-based URL switcher.

The Core Idea

Your React component doesn't care whether the URL it's calling points to a real server or a mock. It sends a request, receives JSON, and renders the data. By swapping the URL from a mock endpoint to the real API later, your component code stays completely unchanged.

Step 1: Create Your Mock Endpoint

Using a tool like MockServer, create a mock endpoint. For example:

  • Method: GET
  • Path: /products
  • Response:
{
  "data": [
    { "id": 1, "name": "Wireless Headphones", "price": 79.99, "stock": 14 },
    { "id": 2, "name": "Mechanical Keyboard", "price": 129.00, "stock": 6 },
    { "id": 3, "name": "USB-C Hub", "price": 39.99, "stock": 32 }
  ],
  "total": 3,
  "page": 1
}

Your mock URL will look like: https://mockserver.in/your-slug/products

Step 2: Fetch in a React Component

Here's a basic product list component using the mock URL:

import { useState, useEffect } from 'react';

const API_BASE = 'https://mockserver.in/your-slug';

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(`${API_BASE}/products`)
      .then(res => {
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        return res.json();
      })
      .then(json => setProducts(json.data))
      .catch(err => setError(err.message))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <p>Loading products...</p>;
  if (error)   return <p>Error: {error}</p>;

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name} — ${p.price}</li>
      ))}
    </ul>
  );
}

Step 3: Use Environment Variables to Switch Between Mock and Real

Hardcoding the mock URL is fine for a quick test, but you should use environment variables so you can switch between mock and real APIs without changing your code.

Create a .env.development file:

REACT_APP_API_BASE=https://mockserver.in/your-slug

And a .env.production file:

REACT_APP_API_BASE=https://api.yourapp.com

Then in your code:

const API_BASE = process.env.REACT_APP_API_BASE;

Now npm start hits the mock, and your production build hits the real API — no code changes required.

If you're using Vite instead of Create React App:

# .env.development
VITE_API_BASE=https://mockserver.in/your-slug
const API_BASE = import.meta.env.VITE_API_BASE;

Step 4: Using Axios Instead of Fetch

If your project uses Axios, the setup is even cleaner with a configured instance:

// src/api/client.js
import axios from 'axios';

const client = axios.create({
  baseURL: process.env.REACT_APP_API_BASE,
  timeout: 10000,
  headers: { 'Content-Type': 'application/json' }
});

export default client;
// In your component
import client from '../api/client';

useEffect(() => {
  client.get('/products')
    .then(res => setProducts(res.data.data))
    .catch(err => setError(err.message))
    .finally(() => setLoading(false));
}, []);

Step 5: Testing Error States with Mocks

This is where mocks become truly valuable. Create a second mock endpoint at /products-error that returns a 500 status. Point your component at it temporarily:

REACT_APP_API_BASE=https://mockserver.in/your-slug-error

Now verify your error UI renders correctly. Switch back when done. No backend coordination needed.

Step 6: Testing with React Query or SWR

If you're using React Query:

import { useQuery } from '@tanstack/react-query';

function ProductList() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['products'],
    queryFn: () =>
      fetch(`${process.env.REACT_APP_API_BASE}/products`)
        .then(res => res.json())
  });

  if (isLoading) return <p>Loading...</p>;
  if (error)     return <p>Error loading products.</p>;

  return (
    <ul>
      {data.data.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

The mock URL works identically here. React Query's caching, refetch, and stale-while-revalidate all work against mock endpoints.

Tips for Working with Mock APIs in React

  • Match the real API contract exactly. Agree with your backend team on the response shape before you mock it, so you don't have to refactor later.
  • Mock dynamic routes too. A tool like MockServer supports paths like /products/{id}, so you can test detail pages as well as list pages.
  • Add realistic delays. Set a 1–2 second delay on your mock to make sure your loading states actually work.
  • Create mocks for all HTTP methods. If your form POSTs to /orders, create a POST mock — don't just test GETs.

Conclusion

Integrating mock APIs into your React development workflow is straightforward and pays immediate dividends. You move faster, test more thoroughly, and ship UIs that handle real-world scenarios — not just the happy path. When the real backend lands, you swap one environment variable and you're done.