Reqord.RedactCassette (reqord v0.4.0)
View SourceMacro for applying custom redaction to HTTP requests and responses within a test.
This module provides a redact_cassette macro that allows users to define custom
redaction functions that are applied to cassette data during recording and replay.
Basic Usage
defmodule MyApp.APITest do
use Reqord.Case
import Reqord.RedactCassette
test "fetches user data with redacted sensitive info" do
redact_cassette redactor: :user_data do
client = Req.new(plug: {Req.Test, MyApp.ReqStub})
{:ok, response} = Req.get(client, url: "https://api.example.com/users/123")
assert response.status == 200
# Email and SSN will be redacted in cassette but preserved in test
assert response.body["email"] =~ "@"
end
end
# Define redaction function
defp redactor(:user_data, _context) do
%{
response_body: fn body ->
body
|> Jason.decode!()
|> put_in(["email"], "[EMAIL_REDACTED]")
|> put_in(["ssn"], "[SSN_REDACTED]")
|> Jason.encode!()
end,
request_headers: fn headers ->
Map.put(headers, "authorization", "[AUTH_REDACTED]")
end
}
end
endNamed Redactors
You can also define named redactors in config and reference them:
# config/test.exs
config :reqord,
redactors: %{
user_api: fn _context ->
%{
response_body: &MyApp.Redactors.redact_user_data/1,
request_headers: &MyApp.Redactors.redact_auth_headers/1
}
end,
financial_api: fn _context ->
%{
response_body: &MyApp.Redactors.redact_financial_data/1
}
end
}
# Then use in tests
redact_cassette redactor: :user_api do
# test code
endRedaction Function Format
Redaction functions receive data and return the redacted version:
response_body_json:(map) -> map- Redacts decoded JSON response bodyresponse_body_raw:(binary) -> binary- Redacts raw binary response bodyrequest_headers:(map) -> map- Redacts request headersresponse_headers:(map) -> map- Redacts response headersurl:(string) -> string- Redacts URL (including query params)
Note: For JSON responses, prefer response_body_json which automatically handles
encoding/decoding using the configured JSON library. Use response_body_raw for
non-JSON content or when you need full control over the binary data.
Advanced Usage
defmodule MyApp.APITest do
use Reqord.Case
import Reqord.RedactCassette
test "complex redaction example" do
redact_cassette redactor: fn _context ->
%{
response_body_json: &redact_nested_secrets/1,
request_headers: fn headers ->
headers
|> Map.put("authorization", "[REDACTED]")
|> Map.put("x-api-key", "[REDACTED]")
end,
url: fn url ->
URI.parse(url)
|> Map.update(:query, nil, fn query ->
if query do
query
|> URI.decode_query()
|> Map.put("token", "[REDACTED]")
|> URI.encode_query()
else
nil
end
end)
|> URI.to_string()
end
}
end do
# test code
end
end
defp redact_nested_secrets(data) when is_map(data) do
Enum.reduce(data, %{}, fn {key, value}, acc ->
cond do
key in ["api_key", "secret", "token"] ->
Map.put(acc, key, "[REDACTED]")
is_map(value) ->
Map.put(acc, key, redact_nested_secrets(value))
is_list(value) ->
Map.put(acc, key, Enum.map(value, &redact_nested_secrets/1))
true ->
Map.put(acc, key, value)
end
end)
end
defp redact_nested_secrets(data), do: data
endIntegration with Reqord.Case
The macro works seamlessly with existing Reqord.Case functionality. It temporarily
installs redaction hooks that are applied during cassette recording and replay.
Summary
Functions
Applies custom redaction within a test block.
Functions
Applies custom redaction within a test block.
Options
:redactor- The redaction function or named redactor to use:cassette- Optional cassette name override (inherits from test context by default)
Examples
# Using a named redactor from config
redact_cassette redactor: :user_api do
# test code
end
# Using an inline function
redact_cassette redactor: fn _context -> %{response_body: &redact_body/1} end do
# test code
end
# With custom cassette name
redact_cassette redactor: :user_api, cassette: "custom_name" do
# test code
end