Last modified: Oct 24, 2026

Mock APIs with responses Library

Testing code that talks to an API can be tricky. Real network calls are slow and unreliable. They can also fail for reasons outside your control.

The responses library solves this problem. It lets you mock HTTP responses in Python tests. Your code runs as if a real API answered, but nothing leaves your machine.

In this guide you will learn how to install and use responses. You will see clear examples with code and output. By the end you will be able to write fast and reliable API tests.

What Is the responses Library?

responses is a Python library for mocking the requests library. It intercepts outgoing HTTP calls and returns canned responses instead.

It was created by the team behind requests-mock alternatives and is widely used in the community. It works well with pytest and unittest.

With responses you can define a URL, a status code, and a body. When your code calls that URL, it gets your fake response back.

This keeps tests fast, deterministic, and offline-friendly. No API keys are needed. No rate limits apply.

Why Mock APIs at All?

Real APIs can be slow. They may go down or change without warning. They may also cost money per request.

Mocking removes these risks. Tests focus on your logic, not the network.

Mocking also lets you simulate edge cases. You can test a 500 error or a timeout on demand. That is hard to do with a live API.

If you already call services like OpenAI, you know how important stable tests are. The same idea applies when you work with OpenAI function calling in Python and want to avoid real API calls in tests.

Installing responses

Install the library with pip. It is small and has no heavy dependencies.


pip install responses

You also need the requests library, since responses patches it. Most projects already have it installed.


pip install requests

Check the installed version to confirm everything is ready.


pip show responses

Name: responses
Version: 0.25.3
Summary: A utility library for mocking out the `requests` Python library.

Your First Mocked Response

Start with a simple function that calls an API. Then mock that call in a test.

The @responses.activate decorator turns mocking on for the test. Inside the test you register a fake response with responses.add.


import requests
import responses

def get_user(user_id):
    # Real code calls the API here
    url = f"https://api.example.com/users/{user_id}"
    return requests.get(url)

@responses.activate
def test_get_user():
    # Register a fake response for the exact URL
    responses.add(
        responses.GET,
        "https://api.example.com/users/1",
        json={"id": 1, "name": "Alice"},
        status=200,
    )

    response = get_user(1)

    # Your code sees a normal requests response
    print(response.status_code)
    print(response.json())

test_get_user()

200
{'id': 1, 'name': 'Alice'}

Notice that get_user did not change at all. The mock lives only in the test. That is the key benefit of responses.

Checking That Calls Were Made

A mock is useful for more than returning data. It also records calls.

Use responses.calls to inspect what your code sent. You can assert on the URL, method, and headers.


import requests
import responses

@responses.activate
def test_call_count():
    responses.add(
        responses.POST,
        "https://api.example.com/items",
        json={"ok": True},
        status=201,
    )

    requests.post("https://api.example.com/items", json={"name": "book"})

    # Inspect recorded calls
    assert len(responses.calls) == 1
    call = responses.calls[0]
    print(call.request.method)
    print(call.request.url)
    print(call.request.body)

test_call_count()

POST
https://api.example.com/items
{"name": "book"}

This pattern is great for verifying payloads. It also helps you catch accidental extra calls.

Mocking Errors and Status Codes

Real APIs fail sometimes. Good tests cover those cases.

Set the status argument to any HTTP code. You can also raise real exceptions to simulate network problems.


import requests
import responses

@responses.activate
def test_server_error():
    responses.add(
        responses.GET,
        "https://api.example.com/data",
        json={"error": "boom"},
        status=500,
    )

    response = requests.get("https://api.example.com/data")
    print(response.status_code)
    print(response.json())

test_server_error()

500
{'error': 'boom'}

To simulate a timeout, pass a body that is an exception instance. The library will raise it when the call is made.


import requests
import responses

@responses.activate
def test_timeout():
    responses.add(
        responses.GET,
        "https://api.example.com/slow",
        body=requests.exceptions.Timeout("too slow"),
    )

    try:
        requests.get("https://api.example.com/slow")
    except requests.exceptions.Timeout as exc:
        print("caught:", exc)

test_timeout()

caught: too slow

Now you can test retry logic and error handling without waiting for a real timeout.

Using responses with pytest

responses ships with a pytest fixture called responses. It is cleaner than the decorator in larger test suites.

Pass the fixture as an argument. Register mocks inside the test. Cleanup happens automatically.


import requests

def test_with_fixture(responses):
    responses.add(
        responses.GET,
        "https://api.example.com/ping",
        json={"pong": True},
        status=200,
    )

    response = requests.get("https://api.example.com/ping")
    assert response.json() == {"pong": True}

$ pytest test_api.py -v
test_api.py::test_with_fixture PASSED

The fixture is handy when you have many tests. It avoids repeating the decorator on every function.

Matching URLs with Regex and Callbacks

Sometimes the URL contains dynamic parts. Use a compiled regex instead of a fixed string.

You can also use responses.add_callback to return a response based on the request. This is useful for pagination or echo endpoints.


import re
import requests
import responses

@responses.activate
def test_regex_and_callback():
    # Match any user id with a regex
    responses.add(
        responses.GET,
        re.compile(r"https://api\.example\.com/users/\d+"),
        json={"name": "Bob"},
        status=200,
    )

    # Callback builds a response from the request
    def echo(request):
        return (200, {"headers": dict(request.headers)})

    responses.add_callback(
        responses.GET,
        "https://api.example.com/echo",
        callback=echo,
    )

    print(requests.get("https://api.example.com/users/42").json())
    print(requests.get("https://api.example.com/echo").json())

test_regex_and_callback()

{'name': 'Bob'}
{'headers': {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}}

Regex matching keeps tests flexible. Callbacks give you full control over the fake response.

Common Pitfalls

You may see an error like ConnectionError when a mock is missing. That means the URL did not match any registered response.

Check the method, URL, and any query string. A trailing slash matters. So do query parameters, unless you use match_querystring or a regex.

Another pitfall is ordering. By default, responses are matched in the order they were registered. Use the match parameter to control this.

Also remember that responses patches requests only. Code using other HTTP clients, like httpx, will not be mocked.

When to Use It in a Real Project

Use responses in unit tests for any module that calls a REST API. It keeps tests isolated and fast.

It also helps when you test data pipelines. For example, a test that parses text from an API can avoid real calls and focus on parsing. The same principle applies when you write tests for tokenization with NLTK in Python and want deterministic input.

For message-based systems, mocking HTTP is only one piece. You may still need real integration tests for brokers. Tools like producing and consuming Kafka messages in Python are often tested separately from HTTP mocks.

Keep unit tests fast with mocks. Keep a small set of integration tests real. That balance gives you confidence without slow suites.

Conclusion

The responses library makes API mocking simple in Python. It patches requests and returns the responses you define.

You learned to install it, register mocks, inspect calls, and simulate errors. You also saw pytest fixtures, regex matching, and callbacks.

Start small. Mock one endpoint in one test. Then expand to cover errors and edge cases.

With responses, your tests become fast, reliable, and easy to read. That is a big win for any project that depends on external APIs.