Skip to main content

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, sync) and requests (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

The context manager API provides proper resource cleanup and doesn't require any additional dependencies.

Using with httpx (async)

import pytest
import inline_snapshot
from http_snapshot.httpx import HttpxAsyncSnapshotClient

@pytest.mark.anyio
@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:my-test-snapshot.json")],
)
async def test_api_call(http_snapshot, is_recording: bool) -> None:
    async with HttpxAsyncSnapshotClient(
        snapshot=http_snapshot,
        is_recording=is_recording,
    ) as client:
        response = await client.get("https://api.example.com/users")
        assert response.status_code == 200
        assert "users" in response.json()

Using with httpx (sync)

import pytest
import inline_snapshot
from http_snapshot.httpx import HttpxSyncSnapshotClient

@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_api_call(http_snapshot, is_recording: bool) -> None:
    with HttpxSyncSnapshotClient(
        snapshot=http_snapshot,
        is_recording=is_recording,
    ) as client:
        response = client.get("https://api.example.com/users")
        assert response.status_code == 200
        assert "users" in response.json()

Using with requests (sync)

import pytest
import inline_snapshot
from http_snapshot.requests import RequestsSnapshotSession

@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_api_call(http_snapshot, is_recording: bool) -> None:
    with RequestsSnapshotSession(
        snapshot=http_snapshot,
        is_recording=is_recording,
    ) as session:
        response = session.get("https://api.example.com/users")
        assert response.status_code == 200
        assert "users" in response.json()

How It Works

# Record new HTTP interactions (makes actual network calls and creates snapshots)
pytest tests/ --http-record --inline-snapshot=create

# Re-record and update existing snapshots (makes actual network calls and updates snapshots)
pytest tests/ --http-record --inline-snapshot=fix

# Replay existing snapshots (default - no network calls made)
pytest tests/

Configuration Options

You can customize what gets captured using SnapshotSerializerOptions:

Using with context managers:

import pytest
import inline_snapshot
from http_snapshot.requests import RequestsSnapshotSession, SnapshotSerializerOptions

@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_with_custom_options(http_snapshot, is_recording: bool) -> None:
    serializer_options = SnapshotSerializerOptions(
        exclude_request_headers=["X-API-Key"],
        include_request=True,
    )

    with RequestsSnapshotSession(
        snapshot=http_snapshot,
        is_recording=is_recording,
        serializer_options=serializer_options,
    ) as session:
        response = 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 snapshots
  • exclude_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": {
        "users": [
          {
            "id": 1,
            "name": "John Doe",
            "email": "john@example.com"
          },
          {
            "id": 2,
            "name": "Jane Smith",
            "email": "jane@example.com"
          }
        ]
      }
    }
  }
]

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

from http_snapshot.httpx import HttpxAsyncSnapshotClient

@pytest.mark.anyio
@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:multi-request-test.json")],
)
async def test_multiple_requests(http_snapshot, is_recording: bool) -> None:
    async with HttpxAsyncSnapshotClient(
        snapshot=http_snapshot,
        is_recording=is_recording,
    ) as client:
        create_response = await 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"]

        get_response = await 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

from http_snapshot.requests import RequestsSnapshotSession, SnapshotSerializerOptions

@pytest.mark.parametrize(
    "http_snapshot",
    [inline_snapshot.external("uuid:auth-test.json")],
)
def test_authenticated_request(http_snapshot, is_recording: bool) -> None:
    serializer_options = SnapshotSerializerOptions(
        exclude_request_headers=["Authorization"]
    )

    with RequestsSnapshotSession(
        snapshot=http_snapshot,
        is_recording=is_recording,
        serializer_options=serializer_options,
    ) as session:
        response = session.get(
            "https://api.example.com/profile",
            headers={"Authorization": "Bearer secret-token"}
        )
        assert response.status_code == 200

Best Practices

  1. Exclude sensitive data: Always exclude headers containing secrets, tokens, or personal data
  2. Review snapshots: Check generated snapshot files into version control and review changes

Metadata

Release files for http-snapshot 0.1.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for http-snapshot 0.1.9
File Size Uploaded
http_snapshot-0.1.9.tar.gz 11.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for http-snapshot 0.1.9
File Interpreter ABI Platform
http_snapshot-0.1.9-py3-none-any.whl Python 3 none any Details

Total release size: 23.9 kB

Release files / http_snapshot-0.1.9.tar.gz

Download URL http_snapshot-0.1.9.tar.gz
Size 11.2 kB
Tags Source
SHA-256 checksum
How to use checksums
22e6a1f0ff2836e14c33724213422d6351fe9513aafbbc5e0608cad9a2c5363c
BLAKE2b-256 checksum
How to use checksums
306d10494f06ba67f9d74f98b25f9db3ae339969b6049e30144d7f161a1b33ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.

Transparency log

Release files / http_snapshot-0.1.9-py3-none-any.whl

Download URL http_snapshot-0.1.9-py3-none-any.whl
Size 12.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
62df93b7c429bd8d836e4dad48b36c473ca88d13652985267a01de9ec4c865c3
BLAKE2b-256 checksum
How to use checksums
8abe2a84ec7f2ac134e7628235768f488f157918f484a9254fa7fa3348d4afbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.9 This release

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page