Configuration & Recording Modes
Configure how VEXFOX records, matches, and replays HTTP requests. Control cassette lifecycle states and customize in-memory redaction rules using `VexfoxConfig`.
1. Recording Modes (`RecordMode`)
VEXFOX exposes four recording modes via the `RecordMode` enum in `vexfox.config`. Each mode dictates how the transport handles incoming HTTP requests:
| Mode | Network Call Allowed? | Persistence Behavior | Best Used For |
|---|---|---|---|
| RecordMode.ONCE | Only if cassette is missing | Writes cassette on first run; replays thereafter | Local development and initial test fixture generation (Default) |
| RecordMode.REPLAY | STRICTLY FORBIDDEN (Zero Sockets) | Read-only from existing cassette; fails if missing | Continuous Integration (CI) and automated regression test suites |
| RecordMode.RECORD | Always makes real call | Overwrites or updates cassette with fresh responses | Refreshing fixtures when external API contracts change |
| RecordMode.NONE | Always makes real call | No recording; complete passthrough | Temporarily bypassing VEXFOX without modifying test code |
from vexfox import RecordMode, use_cassette
import httpx
# Explicitly enforce offline replay mode:
with use_cassette("fixtures/orders.json", mode=RecordMode.REPLAY):
response = httpx.get("https://api.example.com/orders")
assert response.status_code == 2002. Semantic Request Matching Rules
When replaying, VEXFOX compares incoming HTTPX requests against recorded interactions using robust semantic criteria rather than brittle raw string matching:
HTTP Method
Matched case-insensitively (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, etc.).
Normalized URL
Schemes and hostnames are lowercased, default ports (`:80`, `:443`) are normalized, and trailing slash differences are handled predictably.
Order-Insensitive Query Parameters
`?sort=desc&page=2` matches `?page=2&sort=desc`. Duplicate query parameters (`?filter=a&filter=b`) are preserved accurately.
Structural JSON Body Comparison
JSON payloads are parsed and matched structurally. Differences in key ordering, indentation whitespace, or float notation (e.g., `1.0` vs `1`) do not trigger false mismatch errors.
3. Customizing Behavior with `VexfoxConfig`
Create a `VexfoxConfig` instance to inject custom sanitizers, adjust the redaction marker, or enforce specific header matching:
from vexfox import VexfoxConfig, use_cassette
import httpx
# Instantiate custom configuration rules
custom_config = VexfoxConfig(
sensitive_headers={"x-tenant-id", "x-signature"},
sensitive_query_params={"session_token", "customer_id"},
sensitive_body_keys={"ssn", "cvv", "credit_card"},
redaction_marker="[REDACTED]",
match_headers=("content-type", "x-api-version"),
)
with use_cassette("fixtures/custom_flow.json", config=custom_config):
response = httpx.post(
"https://api.example.com/v2/process",
headers={"X-Tenant-Id": "tenant_99812", "Content-Type": "application/json"},
json={"ssn": "000-12-3456", "item": "laptop"},
)
assert response.status_code == 200| Field | Type | Default | Description |
|---|---|---|---|
| sensitive_headers | Set[str] | Authorization, Cookie, ApiKey, etc. | Headers replaced with redaction marker before disk write. |
| sensitive_query_params | Set[str] | api_key, token, secret, password, etc. | Query string parameters scrubbed from the recorded URI. |
| sensitive_body_keys | Set[str] | password, secret, client_secret, etc. | Keys recursively scrubbed in JSON payloads. |
| redaction_marker | str | "[REDACTED]" | String value substituted in place of scrubbed secrets. |
| match_headers | Tuple[str, ...] | () (Empty by default) | Specific headers to include in semantic request matching. |