http-snapshot is a pytest plugin that snapshots requests made with popular Python HTTP clients.
Project description
http-snapshot
http-snapshot is a pytest plugin that captures and snapshots HTTP requests/responses made with popular Python HTTP clients like httpx and requests. It uses inline-snapshot to store HTTP interactions as JSON files, enabling fast and reliable HTTP testing without making actual network calls.
Features
- 🚀 Support for multiple HTTP clients:
httpx(async) andrequests(sync) - 📸 Automatic HTTP interaction capture: Records both requests and responses
- 🔒 Security-aware: Automatically excludes sensitive headers like authorization and cookies
- ⚙️ Configurable: Control what gets captured and what gets excluded
- 🧪 pytest integration: Works seamlessly with your existing pytest test suite
- 📁 External snapshots: Stores snapshots in organized JSON files
Installation
pip install http-snapshot
For specific HTTP client support:
# For httpx support
pip install http-snapshot[httpx]
# For requests support
pip install http-snapshot[requests]
# For both
pip install http-snapshot[httpx,requests]
Quick Start
Using with httpx (async)
import httpx
import pytest
import inline_snapshot
@pytest.mark.anyio
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
async def test_api_call(snapshot_httpx_client: httpx.AsyncClient) -> None:
# This will be captured on first run, replayed on subsequent runs
response = await snapshot_httpx_client.get("https://api.example.com/users")
assert response.status_code == 200
assert "users" in response.json()
Using with requests (sync)
import requests
import pytest
import inline_snapshot
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_api_call(snapshot_requests_session: requests.Session) -> None:
# This will be captured on first run, replayed on subsequent runs
response = snapshot_requests_session.get("https://api.example.com/users")
assert response.status_code == 200
assert "users" in response.json()
How It Works
Live Mode vs Replay Mode
The plugin operates in two modes:
- Live Mode: When
HTTP_SNAPSHOT_LIVE=1is set, actual HTTP requests are made and responses are captured - Replay Mode: When not in live mode, previously captured responses are replayed
Running in Live Mode
# Capture new snapshots
HTTP_SNAPSHOT_LIVE=1 pytest tests/
# Replay existing snapshots (default)
pytest tests/
Configuration Options
You can customize what gets captured using SnapshotSerializerOptions:
import pytest
import inline_snapshot
from http_snapshot._serializer import SnapshotSerializerOptions
@pytest.mark.parametrize(
"http_snapshot, http_snapshot_serializer_options",
[
(
inline_snapshot.external("uuid:my-test-snapshot.json"),
SnapshotSerializerOptions(
exclude_request_headers=["X-API-Key"],
include_request=True, # Include request details in snapshot
),
),
],
)
def test_with_custom_options(
snapshot_requests_session: requests.Session,
http_snapshot_serializer_options: SnapshotSerializerOptions,
) -> None:
response = snapshot_requests_session.get(
"https://api.example.com/protected",
headers={"X-API-Key": "secret-key"}
)
assert response.status_code == 200
Available Options
include_request: Whether to include request details in snapshots (default:True)exclude_request_headers: List of request headers to exclude from snapshotsexclude_response_headers: List of response headers to exclude from snapshots
By default, the following sensitive headers are always excluded:
- Request:
authorization,cookie - Response:
set-cookie,www-authenticate,proxy-authenticate,authentication-info,proxy-authentication-info,transfer-encoding,content-encoding
Snapshot Format
Snapshots are stored as JSON files with the following structure:
[
{
"request": {
"method": "GET",
"url": "https://api.example.com/users",
"headers": {
"host": "api.example.com",
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"connection": "keep-alive",
"user-agent": "python-httpx/0.28.1"
},
"body": ""
},
"response": {
"status_code": 200,
"headers": {
"date": "Thu, 21 Aug 2025 15:49:45 GMT",
"content-type": "application/json; charset=utf-8",
"connection": "keep-alive",
"server": "nginx/1.18.0"
},
"body": "{\n \"users\": [\n {\n \"id\": 1,\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n ]\n}"
}
}
]
Content Encoding
The plugin intelligently handles different content types:
- JSON: Formatted with proper indentation for readability
- Text: Stored as UTF-8 strings
- Binary: Base64 encoded
Advanced Examples
Testing API with Multiple Requests
@pytest.mark.anyio
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:multi-request-test.json")],
)
async def test_multiple_requests(snapshot_httpx_client: httpx.AsyncClient) -> None:
# Create a user
create_response = await snapshot_httpx_client.post(
"https://api.example.com/users",
json={"name": "Alice", "email": "alice@example.com"}
)
assert create_response.status_code == 201
user_id = create_response.json()["id"]
# Fetch the user
get_response = await snapshot_httpx_client.get(
f"https://api.example.com/users/{user_id}"
)
assert get_response.status_code == 200
assert get_response.json()["name"] == "Alice"
Testing with Authentication
@pytest.mark.parametrize(
"http_snapshot, http_snapshot_serializer_options",
[
(
inline_snapshot.external("uuid:auth-test.json"),
SnapshotSerializerOptions(exclude_request_headers=["Authorization"]),
),
],
)
def test_authenticated_request(
snapshot_requests_session: requests.Session,
http_snapshot_serializer_options,
) -> None:
# The Authorization header will be excluded from the snapshot
response = snapshot_requests_session.get(
"https://api.example.com/profile",
headers={"Authorization": "Bearer secret-token"}
)
assert response.status_code == 200
Best Practices
- Exclude sensitive data: Always exclude headers containing secrets, tokens, or personal data
- Review snapshots: Check generated snapshot files into version control and review changes
- Use live mode sparingly: Only run in live mode when you need to update snapshots
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file http_snapshot-0.1.0.tar.gz.
File metadata
- Download URL: http_snapshot-0.1.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb75e98868f1839b0c29ef38d582234554f1d2c66e87612960875a24b2e82331
|
|
| MD5 |
4cd177535393a285209f908e7916fe09
|
|
| BLAKE2b-256 |
aaf8184c85f358792f8d1b26a8723e8c8d576cab65ce8bbcf3a875637b08fa45
|
File details
Details for the file http_snapshot-0.1.0-py3-none-any.whl.
File metadata
- Download URL: http_snapshot-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d5cb47c19acfbefaecc0ac53017065cc899fb9994a24365d454d52d49c72e44
|
|
| MD5 |
da41a203df1d2cbf2a61726650b68d4b
|
|
| BLAKE2b-256 |
e87343c5c280f51ac9b4202f4ffe5ed7561e3dfc4d83ed2dd53469c142274f34
|