Hello Elixir community! ![]()
I’m excited to announce the first release of ReqCassette, a VCR-style record-and-replay library specifically designed for Req.
What is ReqCassette?
ReqCassette captures HTTP responses to JSON files (“cassettes”) and replays them in subsequent test runs, making your tests:
- Faster - No network calls after initial recording
- Deterministic - Same response every time
- Offline-capable - Work without internet once cassettes are recorded
- Cost-effective - Perfect for testing paid APIs (like LLM services!)
Why build this
ReqCassette leverages Req’s native testing infrastructure instead of global mocking, making it process-isolated and fully compatible with ExUnit’s async testing.
Quick Example
defmodule MyApp.APITest do
use ExUnit.Case, async: true
test "fetches user data" do
# First run: records to cassette
# Subsequent runs: instant replay!
response = Req.get!(
"https://api.example.com/users/1",
plug: {ReqCassette.Plug, %{cassette_dir: "test/cassettes"}}
)
assert response.status == 200
assert response.body["name"] == "Alice"
end
end
Created with ReqLLM in mind
One of my favorite use cases is testing LLM applications with
ReqLLM:
{:ok, response} = ReqLLM.generate_text(
"anthropic:claude-sonnet-4-20250514",
"Explain recursion",
max_tokens: 100,
req_http_options: [
plug: {ReqCassette.Plug, %{cassette_dir: "test/cassettes"}}
]
)
First call costs money and it’s slow, but every subsequent test is fast and
FREE - the response is replayed from the cassette! This makes testing with LLMs
much more practical.
How It Works
ReqCassette uses Req’s :plug option to intercept requests:
- First request → Forwards to real server → Saves response to JSON →
Returns response - Subsequent requests → Loads JSON cassette → Returns saved response
Cassettes are matched by HTTP method, path, query string, and request body,
creating a unique MD5 hash for the filename.
What’s Next?
Some ideas for future versions:
- Additional recording modes (
:once,:none,:all) - Custom cassette naming
- Header-based matching
- Cassette expiration/TTL
- Request filtering/sanitization helpers
Feedback Welcome!
This is the first release, and I’d love to hear your thoughts:
- Are there features you’d like to see?
- Any issues or bugs to report?
Thanks for reading, and happy testing! ![]()
Resources
- Hex: hex.pm/packages/req_cassette
- Documentation: hexdocs.pm/req_cassette
- ReqLLM Integration Guide:
ReqLLM Integration - GitHub:
Note: Special thanks to the Req maintainers for building such a fantastic HTTP
client with great testing support, and to the ReqLLM maintainers for creating a
promising and foundational library that makes Elixir shine in the new LLM
space!




















