Skip to content

Commit b913b74

Browse files
committed
Add agent context.
1 parent 716fad9 commit b913b74

File tree

3 files changed

+199
-1
lines changed

3 files changed

+199
-1
lines changed

async-http-capture.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
1717
"source_code_uri" => "https://github.com/socketry/async-http-capture.git",
1818
}
1919

20-
spec.files = Dir.glob(["{lib}/**/*", "*.md"], File::FNM_DOTMATCH, base: __dir__)
20+
spec.files = Dir.glob(["{context,lib}/**/*", "*.md"], File::FNM_DOTMATCH, base: __dir__)
2121

2222
spec.required_ruby_version = ">= 3.2"
2323

context/getting-started.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Getting Started
2+
3+
This guide explains how to get started with `async-http-capture`, a Ruby gem for recording and replaying HTTP requests using Protocol::HTTP.
4+
5+
## Installation
6+
7+
Add the gem to your project:
8+
9+
~~~ bash
10+
$ bundle add async-http-capture
11+
~~~
12+
13+
## Core Concepts
14+
15+
`async-http-capture` has several core concepts:
16+
17+
- A {ruby Async::HTTP::Capture::Middleware} which captures HTTP requests and responses as they pass through your application.
18+
- An {ruby Async::HTTP::Capture::Interaction} which represents a single HTTP request/response pair with lazy Protocol::HTTP object construction.
19+
- A {ruby Async::HTTP::Capture::Cassette} which is a collection of interactions that can be loaded from and saved to JSON files.
20+
- A {ruby Async::HTTP::Capture::CassetteStore} which provides content-addressed storage, saving each interaction to a separate file named by its content hash.
21+
- A {ruby Async::HTTP::Capture::ConsoleStore} which logs interactions to the console for debugging purposes.
22+
23+
## Usage
24+
25+
The basic workflow involves:
26+
27+
1. **Recording**: Capture HTTP interactions using middleware
28+
2. **Storage**: Save interactions using pluggable store backends
29+
3. **Replay**: Load and replay recorded interactions
30+
31+
### Basic Recording
32+
33+
Here's how to record HTTP interactions to files:
34+
35+
~~~ ruby
36+
require "async/http/capture"
37+
38+
# Create a store that saves to content-addressed files:
39+
store = Async::HTTP::Capture::CassetteStore.new("interactions")
40+
41+
# Create your application
42+
app = ->(request) { Protocol::HTTP::Response[200, {}, ["OK"]] }
43+
44+
# Wrap it with recording middleware:
45+
middleware = Async::HTTP::Capture::Middleware.new(app, store: store)
46+
47+
# Make requests - they will be automatically recorded:
48+
request = Protocol::HTTP::Request["GET", "/users"]
49+
response = middleware.call(request)
50+
# This creates a file like interactions/a1b2c3d4e5f67890.json
51+
~~~
52+
53+
### Recording with Console Output
54+
55+
For debugging, you can log interactions to the console:
56+
57+
~~~ ruby
58+
# Create a console store for debugging:
59+
console_store = Async::HTTP::Capture::ConsoleStore.new
60+
middleware = Async::HTTP::Capture::Middleware.new(app, store: console_store)
61+
62+
# This will log interactions to console:
63+
middleware.call(request)
64+
# Output: "Recorded: GET /users"
65+
~~~
66+
67+
### Loading and Replaying Interactions
68+
69+
~~~ ruby
70+
# Load recorded interactions:
71+
cassette = Async::HTTP::Capture::Cassette.load("interactions")
72+
73+
# Replay them against your application:
74+
cassette.each do |interaction|
75+
request = interaction.request # Lazy Protocol::HTTP::Request construction
76+
response = app.call(request) # Send to your app
77+
puts "#{request.method} #{request.path} -> #{response.status}"
78+
end
79+
~~~
80+
81+
## Recording HTTP Requests and Responses
82+
83+
By default, only requests are recorded. To capture responses as well:
84+
85+
~~~ ruby
86+
middleware = Async::HTTP::Capture::Middleware.new(
87+
app,
88+
store: store,
89+
record_response: true
90+
)
91+
92+
response = middleware.call(request)
93+
# Both request and response are now recorded
94+
~~~
95+
96+
## Content-Addressed Storage
97+
98+
Each interaction is saved to a file named by its content hash, providing several benefits:
99+
100+
~~~
101+
interactions/
102+
├── a1b2c3d4e5f67890.json # GET /users
103+
├── f67890a1b2c3d4e5.json # POST /orders
104+
└── 1234567890abcdef.json # GET /health
105+
~~~
106+
107+
Benefits:
108+
- **Automatic de-duplication**: Identical interactions → same filename
109+
- **Parallel-safe**: Multiple processes can write without conflicts
110+
- **Content integrity**: Hash verifies file contents
111+
- **Git-friendly**: Stable filenames for version control
112+
113+
## Application Warmup
114+
115+
A common use case is warming up your application with recorded traffic:
116+
117+
~~~ ruby
118+
require "async/http/capture"
119+
120+
# Step 1: Record requests during development/testing
121+
endpoint = Async::HTTP::Endpoint.parse("https://api.example.com")
122+
store = Async::HTTP::Capture::CassetteStore.new("warmup_interactions")
123+
124+
recording_middleware = Async::HTTP::Capture::Middleware.new(
125+
nil,
126+
store: store
127+
)
128+
129+
client = Async::HTTP::Client.new(endpoint, middleware: [recording_middleware])
130+
131+
# Make the requests you want to record
132+
Async do
133+
client.get("/health")
134+
client.get("/api/popular-items")
135+
client.post("/api/user-sessions", {user_id: 123})
136+
end
137+
138+
# Step 2: Use recorded interactions to warm up your application
139+
cassette = Async::HTTP::Capture::Cassette.load("warmup_interactions")
140+
app = MyApplication.new
141+
142+
puts "Warming up with #{cassette.interactions.size} recorded interactions..."
143+
cassette.each do |interaction|
144+
request = interaction.request
145+
begin
146+
app_response = app.call(request)
147+
puts "Warmed up #{request.method} #{request.path} -> #{app_response.status}"
148+
rescue => error
149+
puts "Warning: #{request.method} #{request.path} -> #{error.message}"
150+
end
151+
end
152+
153+
puts "Warmup complete!"
154+
~~~
155+
156+
## Custom Storage Backends
157+
158+
You can create custom storage backends by implementing the {ruby Async::HTTP::Capture::Store} interface:
159+
160+
~~~ ruby
161+
class MyCustomStore
162+
include Async::HTTP::Capture::Store
163+
164+
def call(interaction)
165+
# Handle the interaction as needed
166+
# e.g., send to a database, external service, etc.
167+
puts "Custom handling: #{interaction.request.method} #{interaction.request.path}"
168+
end
169+
end
170+
171+
# Use your custom store
172+
custom_store = MyCustomStore.new
173+
middleware = Async::HTTP::Capture::Middleware.new(app, store: custom_store)
174+
~~~
175+
176+
## Key Features
177+
178+
- **Pure Protocol::HTTP**: Works directly with Protocol::HTTP objects, no lossy conversions
179+
- **Content-Addressed Storage**: Each interaction saved as separate JSON file with content hash
180+
- **Parallel-Safe**: Multiple processes can record simultaneously without conflicts
181+
- **Flexible Stores**: Pluggable storage backends (files, console logging, etc.)
182+
- **Complete Headers**: Full round-trip serialization including `fields` and `tail`
183+
- **Error Handling**: Captures network errors and connection issues
184+
- **Lazy Construction**: Protocol::HTTP objects are constructed on-demand for memory efficiency
185+
186+
This makes `async-http-capture` ideal for testing, debugging, application warmup, and HTTP traffic analysis scenarios.

context/index.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Automatically generated context index for Utopia::Project guides.
2+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3+
---
4+
description: A HTTP request and response capture.
5+
metadata:
6+
documentation_uri: https://socketry.github.io/async-http-capture/
7+
source_code_uri: https://github.com/socketry/async-http-capture.git
8+
files:
9+
- path: getting-started.md
10+
title: Getting Started
11+
description: This guide explains how to get started with `async-http-capture`, a
12+
Ruby gem for recording and replaying HTTP requests using Protocol::HTTP.

0 commit comments

Comments
 (0)