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 GitHub API and the responses it returns.

#[cfg(all(feature = "proxy", feature = "record"))]
#[test]
fn record_github_api_with_forwarding_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://api.github.com", |rule| {
rule.filter(|when| {
when.any_request(); // Ensure all requests are forwarded.
});
});
let recording = server.record(|rule| {
rule
// Specify which headers to record.
// Only the headers listed here will be captured and stored
// as part of the recorded mock. This selective recording is
// necessary because some headers may vary between requests
// and could cause issues when replaying the mock later.
// For instance, headers like 'Authorization' or 'Date' may
// change with each request.
.record_request_header("User-Agent")
.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.url("/repos/torvalds/linux"))
// GitHub requires us to send a user agent header
.header("User-Agent", "httpmock-test")
.send()
.unwrap();
// Since the request was forwarded, we should see a GitHub API response.
assert_eq!(response.status().as_u16(), 200);
assert_eq!(true, response.text().unwrap().contains("\"private\":false"));
// Save the recording to
// "target/httpmock/recordings/github-torvalds-scenario_<timestamp>.yaml".
recording
.save("github-torvalds-scenario")
.expect("cannot store scenario on disk");
}

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 = "record", feature = "experimental"))]
#[test]
fn record_with_proxy_test() {
// Start a mock server to act as a proxy for the HTTP client
let server = MockServer::start();
// Configure the mock server to proxy all incoming requests
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 = server.record(|rule| {
rule.filter(|when| {
when.any_request(); // Record all requests
});
});
// Create an HTTP client configured to route requests
// through the mock proxy server
let github_client = Client::builder()
// Set the proxy URL to the mock server's URL
.proxy(reqwest::Proxy::all(server.base_url()).unwrap())
.build()
.unwrap();
// Send a GET request using the client, which will be proxied by the mock server
let response = github_client.get(server.base_url()).send().unwrap();
// Verify that the response matches the expected mock response
assert_eq!(response.text().unwrap(), "This is a mock response");
// Save the recorded HTTP interactions to a file for future reference or testing
recording
.save("my_scenario_name")
.expect("could not save the recording");
}