Let's say I want to write a client for an HTTP API where the actual HTTP implementation can be swapped out. So the usage would be like this:
fn main() {
let http_client = reqwest::blocking::Client::new();
let api_client = ApiClient::new(http_client);
api_client.get_something();
}
The http_client
is consumed.
The library would look like this:
struct ApiClient {
http_client: reqwest::blocking::Client
}
impl ApiClient {
fn new(http_client: reqwest::blocking::Client) -> ApiClient {
ApiClient {
http_client
}
}
fn get_something(&self) {
let a = &self.http_client;
println!("{}", a.get("https://httpbin.org/get").send().unwrap().text().unwrap());
}
}
Now the user of the library might want to do other things with the HTTP connection and would therefore prefer if the http_client
wasn't consumed. I can change my library to this:
struct ApiClient<'a> {
http_client: &'a reqwest::blocking::Client
}
impl ApiClient<'_> {
fn new(http_client: &reqwest::blocking::Client) -> ApiClient {
ApiClient {
http_client
}
}
fn get_something(&self) {
let a = self.http_client;
println!("{}", a.get("https://httpbin.org/get").send().unwrap().text().unwrap());
}
}
But then the user decides that she wants to extract the initialization code to a function:
fn main() {
let api_client = make_client();
api_client.get_something();
}
fn make_client() -> ApiClient {
let http_client = reqwest::blocking::Client::new();
let api_client = ApiClient::new(&http_client);
api_client
}
This isn't possible of course because the ApiClient
would live longer than the reqwest::blocking::Client
.
Is there an idiomatic way to let my library optionally consume the HTTP client?