use async_trait::async_trait;
use reqwest::Client;
use std::collections::HashMap;
use super::{HttpClient, Method, Request, Response};
use crate::error::Result;
use crate::USER_AGENT;
#[derive(Debug, Clone)]
pub struct ReqwestClient {
client: Client,
}
impl ReqwestClient {
pub fn new() -> Result<Self> {
let client = Client::builder().user_agent(USER_AGENT).build()?;
Ok(Self { client })
}
pub const fn with_client(client: Client) -> Self {
Self { client }
}
}
impl Default for ReqwestClient {
fn default() -> Self {
Self::new().expect("Failed to create default reqwest client")
}
}
#[async_trait]
impl HttpClient for ReqwestClient {
async fn send(&self, request: Request) -> Result<Response> {
let mut builder = match request.method {
Method::Get => self.client.get(&request.url),
Method::Post => self.client.post(&request.url),
};
if !request.query.is_empty() {
builder = builder.query(&request.query.iter().collect::<Vec<(&String, &String)>>());
}
for (key, value) in &request.headers {
builder = builder.header(key, value);
}
if let Some(body) = request.body {
builder = builder.body(body);
}
let response = builder.send().await?;
let status = response.status().as_u16();
let headers: HashMap<String, String> = response
.headers()
.iter()
.filter_map(|(k, v)| {
v.to_str()
.ok()
.map(|v| (k.as_str().to_string(), v.to_string()))
})
.collect();
let body = response.text().await?;
Ok(Response {
status,
headers,
body,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reqwest_client_creation() {
let client = ReqwestClient::new();
assert!(client.is_ok());
}
#[test]
fn test_reqwest_client_default() {
let client = ReqwestClient::default();
let _ = client;
}
}