Skip to content

Recording

httpmock provides functionality to record both requests to third-party services and their responses. There are two strategies how you can achieve that: Forwarding and Proxy.

Forwarding Strategy

The forwarding feature is the easier method for intercepting and recording responses from third-party services. However, it requires you to change the client’s base URL to direct requests to the mock server’s address.

When using the forwarding strategy, your client sends requests to an httpmock mock server. The mock server forwards requests that match the criteria defined in the When structure to a predefined target base URL.

Let’s have a look at a basic forwarding example:

// Initialize the mock server for testing
let server = MockServer::start();
// Configure the server to forward all requests to the GitHub API,
// instead of using mocked responses. The 'when' configuration allows
// setting conditions for when forwarding should occur, using the same
// structure familiar from creating mocks.
server.forward_to("https://github.com", |rule| {
rule.filter(|when| {
when.any_request(); // Ensure all requests are forwarded.
});
});

You can use the forwarding functionality to record requests sent to the remote service.

Full Example

The following example demonstrates how you can use the forwarding feature to record requests sent to the httpmock website and the responses it returns.

#[cfg(all(feature = "record"))]
#[test]
fn record_with_forwarding_example_test() {
// Let's create our mock server for the test
let server = MockServer::start();
// We configure our server to forward the request to the target
// host instead of answering with a mocked response. The 'when'
// variable lets you configure rules under which forwarding
// should take place.
server.forward_to("https://httpmock.rs", |rule| {
rule.filter(|when| {
when.any_request(); // Ensure all requests are forwarded.
});
});
let recording = server.record(|rule| {
rule.filter(|when| {
when.any_request(); // Ensure all requests are recorded.
});
});
// Now let's send an HTTP request to the mock server. The request
// will be forwarded to the GitHub API, as we configured before.
let client = Client::new();
let response = client.get(server.base_url()).send().unwrap();
// Since the request was forwarded, we should see a GitHub API response.
assert_eq!(response.status().as_u16(), 200);
assert!(response
.text()
.unwrap()
.contains("Simple yet powerful HTTP mocking library for Rust"));
// Save the recording to
// "target/httpmock/recordings/website-via-forwarding_<timestamp>.yaml".
let recording_file_path = recording
.save("website-via-forwarding")
.expect("cannot store recording on disk");
// Start a new mock server instance for playback
let playback_server = MockServer::start();
// Load the recorded interactions into the new mock server
playback_server.playback(recording_file_path);
// Send a request to the playback server and verify the response
// matches the recorded data
let response = client.get(playback_server.base_url()).send().unwrap();
assert_eq!(response.status().as_u16(), 200);
assert!(response
.text()
.unwrap()
.contains("Simple yet powerful HTTP mocking library for Rust"));
}

Proxy Strategy

The proxy feature in httpmock, while functional on its own, is particularly useful for recording in scenarios where modifying or injecting the base URL used by the client is not possible.

Many SDKs, APIs, and HTTP clients support proxy server configuration. For example, the reqwest crate allows you to set up a proxy server with the following configuration:

// Create a client using the reqwest crate with a configured proxy
let client = Client::builder()
.proxy(reqwest::Proxy::all("my-proxy-server:8080").unwrap())
.build()
.unwrap();
// Send a GET request and unwrap the result
let response = client.get("https://github.com").send().unwrap();

In this example, each request is routed through the proxy server rather than directly to the requested domain host. The proxy server then tunnels or forwards the request to the target host, which is github.com in this case.

When configured as a proxy, httpmock can intercept, record, and forward both requests and responses.

Full Example

#[cfg(all(feature = "proxy", feature = "https", feature = "record"))]
#[test]
fn record_with_proxy_example_test() {
use httpmock::RecordingRuleBuilder;
// Start a mock server to act as a proxy for the HTTP client
let recording_proxy_server = MockServer::start();
// Configure the mock server to proxy all incoming requests
recording_proxy_server.proxy(|rule| {
rule.filter(|when| {
when.any_request(); // Intercept all requests
});
});
// Set up recording on the mock server to capture all proxied
// requests and responses
let recording = recording_proxy_server.record(|rule: RecordingRuleBuilder| {
rule.filter(|when| {
when.any_request(); // Record all requests
});
});
// Create an HTTP client configured to route requests
// through the mock proxy server
let client = Client::builder()
// Set the proxy URL to the mock server's URL
.proxy(reqwest::Proxy::all(recording_proxy_server.base_url()).unwrap())
.build()
.unwrap();
// Send a GET request using the client, which will be proxied by the mock server
let response = client.get("https://httpmock.rs").send().unwrap();
// Since the request was forwarded, we should see a GitHub API response.
assert_eq!(response.status().as_u16(), 200);
assert!(response
.text()
.unwrap()
.contains("Simple yet powerful HTTP mocking library for Rust"));
// Save the recording to
// "target/httpmock/recordings/website-via-proxy_<timestamp>.yaml".
let recording_file_path = recording
.save("website-via-proxy")
.expect("could not save the recording");
// Start a new mock server instance for playback
let playback_server = MockServer::start();
// Load the recorded interactions into the new mock server
playback_server.playback(recording_file_path);
// Send a request to the playback server and verify the response
// matches the recorded data
let response = client.get(playback_server.base_url()).send().unwrap();
assert_eq!(response.status().as_u16(), 200);
assert!(response
.text()
.unwrap()
.contains("Simple yet powerful HTTP mocking library for Rust"));
}