Async::HTTP::Capture
A Ruby gem for recording and replaying HTTP requests using Protocol::HTTP
. Features timestamped storage, parallel-safe recording, and flexible store backends.
Features
- Pure Protocol::HTTP: Works directly with Protocol::HTTP objects, no lossy conversions
- Timestamped Storage: Each interaction saved as separate JSON file with timestamp
- Parallel-Safe: Multiple processes can record simultaneously without conflicts
- Flexible Stores: Pluggable storage backends (files, console logging, etc.)
- Complete Headers: Full round-trip serialization including
fields
andtail
- Error Handling: Captures network errors and connection issues
Usage
Please browse the source code index or refer to the guides below.
Getting Started
This guide explains how to get started with async-http-capture
, a Ruby gem for recording and replaying HTTP requests using Protocol::HTTP.
Falcon Integration
This guide explains how to integrate async-http-capture
with Falcon web server for recording and replaying HTTP interactions.
Basic Recording to Files
require "async/http/capture"
# Create a store that saves to timestamped files:
store = Async::HTTP::Capture::CassetteStore.new("interactions")
# Create middleware:
app = ->(request) { Protocol::HTTP::Response[200, {}, ["OK"]] }
middleware = Async::HTTP::Capture::Middleware.new(app, store: store)
# Record interactions:
request = Protocol::HTTP::Request["GET", "/users"]
response = middleware.call(request)
Recording to Console Log
# Create a console store for debugging:
console_store = Async::HTTP::Capture::ConsoleStore.new
middleware = Async::HTTP::Capture::Middleware.new(app, store: console_store)
# This will log interactions to console:
middleware.call(request)
# Output: "Recorded: GET /users"
Loading and Replaying
# Load recorded interactions:
cassette = Async::HTTP::Capture::Cassette.load("interactions")
# Replay them:
cassette.each do |interaction|
request = interaction.request # Lazy construction
response = app.call(request) # Send to your app
end
Recording with Responses
# Record both requests and responses:
middleware = Async::HTTP::Capture::Middleware.new(
app,
store: store,
record_response: true
)
response = middleware.call(request)
# Both request and response are now recorded
Architecture
Middleware -> Store.call(interaction) -> [CassetteStore | ConsoleStore | ...]
- Middleware: Pure capture logic, creates Interaction objects with Protocol::HTTP data
- Store Interface: Generic
call(interaction)
method for pluggable backends - Stores: Handle serialization, filtering, persistence, or logging
- Interaction: Simple data container with lazy Protocol::HTTP object construction
Timestamped Storage
Each interaction is saved to a file named with timestamp, process ID, and object ID:
recordings/
├── 20250821-105406-271633-12345-67890.json # GET /users
├── 20250821-105006-257022-12346-67891.json # POST /orders
└── 20250820-101234-567890-12347-67892.json # GET /health
Benefits:
- Chronological ordering: Files sorted by timestamp
- Parallel-safe: Multiple processes can write without conflicts
- Human-readable: Timestamps are easy to understand
Store Implementations
CassetteStore
Saves interactions to timestamped JSON files in a directory.
ConsoleStore
Logs interactions via the Console gem with different levels based on success/failure.
Custom Stores
Implement the Store
interface:
class MyStore
include Async::HTTP::Capture::Store
def call(interaction)
# Handle the interaction as needed
end
end
Testing
bundle exec sus
The gem includes comprehensive tests using the Sus testing framework with 41 tests and 101 assertions.