async-http-capture 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/context/getting-started.md +186 -0
- data/context/index.yaml +12 -0
- data/design.md +771 -0
- data/lib/async/http/capture/cassette.rb +69 -0
- data/lib/async/http/capture/cassette_store.rb +47 -0
- data/lib/async/http/capture/console_store.rb +61 -0
- data/lib/async/http/capture/interaction.rb +269 -0
- data/lib/async/http/capture/interaction_tracker.rb +144 -0
- data/lib/async/http/capture/middleware.rb +117 -0
- data/lib/async/http/capture/version.rb +12 -0
- data/lib/async/http/capture.rb +22 -0
- data/license.md +21 -0
- data/readme.md +133 -0
- data/releases.md +5 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1daaf4df163cc364474c3fa2317fc470599b93291f172612534c251de4213f7d
|
4
|
+
data.tar.gz: eeb94b760ea184040e56a2d334e9eb655864f4275d3e9397ae99f19ca3f237c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aec6884a20a7bf778d2a420927893c0bb24cbf988554b6a1c23fa8336abe332c37037663060e84e04acf0fdc365d1fa38196d934bcda1e824dabcdf5276c3ab9
|
7
|
+
data.tar.gz: b3cdf504d73f9ec34dea3e0faf4db09f813c616fc800b1922149e27687a5c02716b06d051e1a0d2626bb203a814c7cc4f4bc2c917e842357354b9b36ccc11993
|
@@ -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.
|
data/context/index.yaml
ADDED
@@ -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.
|