API mocking is the practice of creating simulated versions of APIs that behave like real services without the actual backend infrastructure. It's a technique, not a tool - you can mock APIs using various methods from simple JSON files to sophisticated service virtualization platforms.
API Mocking
Simulating API behavior to enable development and testing without real backend services.
Why Mock APIs?
Speed up development: Backend API takes 3 sprints to build? Don't wait. Mock the endpoints based on the agreed contract and start building the frontend today. When the real API is ready, swap out the mock.
Isolate dependencies: Your app calls 5 external APIs. Any of them being down breaks your development and testing. Mocking isolates your code from external failures.
Enable testing: Tests that call real APIs are slow, flaky, and expensive. They fail when the network is slow, when the API is rate-limited, or when test data gets cleaned up. Mocked tests run in milliseconds, every time.
Reduce costs: AWS, Stripe, Twilio, OpenAI - they all charge per request. Running your test suite 100 times a day against real APIs adds up fast. Mocks are free.
Test edge cases: How does your app handle a 500 error? A 30-second timeout? A response with 10,000 items? These scenarios are hard to trigger with real APIs but trivial to mock.
Mocking Approaches
| Approach | How It Works | Best For |
|---|---|---|
| Static responses | Return fixed JSON files | Simple demos, basic tests |
| Programmatic mocks | Code that generates responses | Dynamic data, complex logic |
| Record/replay | Capture real responses, replay later | Integration testing, legacy APIs |
| Contract-based | Generate from OpenAPI/Swagger | API-first development |
| Service virtualization | Full simulation of backend behavior | Enterprise, complex systems |
Mocking at Different Levels
Network level (MSW, nock): Intercepts actual HTTP requests. Your code makes real fetch/axios calls, but they're caught and handled by the mock. Best for testing because it exercises real networking code.
Client level (jest.mock): Replaces the API client module entirely. Faster but less realistic - doesn't test the actual HTTP layer.
Server level (json-server, WireMock): Runs a real HTTP server that responds to requests. Can be shared across team, used in CI, accessed by any language.
What to Mock
Mock external services: Payment gateways, email services, third-party APIs - anything outside your control.
Mock slow or expensive operations: AI inference, image processing, long database queries - if it's slow or costs money, consider mocking for most tests.
Don't mock your own code: If you mock everything, you test nothing. The goal is to isolate external dependencies, not to avoid testing your actual implementation.
Creating Effective Mocks
Match the real response structure exactly:
If the real API returns {data: {users: [...]}} and your mock returns {users: [...]}, you'll have bugs when switching. Keep structures identical.
Include realistic data:
{name: "test"} doesn't catch issues that {name: "José García-López"} would. Use varied, realistic data.
Mock error cases: A mock that always succeeds is incomplete. Create mocks for:
- 400 validation errors
- 401 authentication failures
- 404 not found
- 500 server errors
- Network timeouts
Add realistic latency: Instant responses hide loading state bugs. Add 50-200ms delay to catch issues with spinners, disabled buttons, and race conditions.
Common Mocking Patterns
Happy path mock: The default - everything works, returns expected data.
Error mock: Throws specific errors to test error handling code.
Empty state mock: Returns empty arrays or null to test "no data" UI.
Slow mock: Adds delays to test loading states and timeouts.
Flaky mock: Randomly fails to test retry logic.
Mocking Best Practices
Keep mocks close to tests: Define mocks near the tests that use them. Shared global mocks become confusing and hard to maintain.
Reset between tests: Clear mock state after each test. Leftover state from previous tests causes mysterious failures.
Type your mocks: In TypeScript, type your mock responses. The compiler catches mismatches between mock and real API types.
Update mocks when APIs change: Outdated mocks are dangerous - tests pass but production breaks. Tie mock updates to API changes.
Don't over-specify: A mock that requires exact request body matching is brittle. Match only what matters for the test.
Common Mistakes
1. Mocks that drift from reality: You update the real API but forget the mock. Tests pass, production fails. Automate mock generation from OpenAPI specs when possible.
2. Testing the mock instead of your code: If your mock has complex logic, you might be testing the mock behavior rather than your actual application.
3. Shared mutable mocks: All tests share one mock that gets modified. Test A changes the mock, test B fails mysteriously. Use fresh mocks for each test.
4. No negative testing: All your mocks return success. You ship, and the first API error crashes your app. Always mock failure cases.
Code Examples
API Mocking with Jest
// api.ts - Your real API client
export async function fetchUser(id: number) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error('User not found');
return res.json();
}
// api.test.ts - Tests with mocking
import { fetchUser } from './api';
// Mock the global fetch
beforeEach(() => {
global.fetch = jest.fn();
});
test('returns user data on success', async () => {
// Setup mock response
(fetch as jest.Mock).mockResolvedValue({
ok: true,
json: async () => ({ id: 1, name: 'John' }),
});
const user = await fetchUser(1);
expect(user.name).toBe('John');
expect(fetch).toHaveBeenCalledWith('/api/users/1');
});
test('throws on 404', async () => {
(fetch as jest.Mock).mockResolvedValue({
ok: false,
status: 404,
});
await expect(fetchUser(999)).rejects.toThrow('User not found');
});
test('handles network error', async () => {
(fetch as jest.Mock).mockRejectedValue(new Error('Network error'));
await expect(fetchUser(1)).rejects.toThrow('Network error');
});Related Terms
Service Virtualization
An enterprise-grade technique for simulating the behavior of dependent services, APIs, and systems that are unavailable or costly to access.
Mock Server
A fake server that simulates API responses for testing and development purposes.
REST API
An architectural style for building web APIs using HTTP methods and stateless communication.
WebSocket
A protocol enabling full-duplex, real-time communication between client and server.