use crate::{HttpClientError, Result};
use bytes::Bytes;
use http::{HeaderMap, StatusCode};
use serde::de::DeserializeOwned;
#[derive(Debug)]
pub struct Response {
status: StatusCode,
headers: HeaderMap,
body: Bytes,
url: url::Url,
}
impl Response {
pub(crate) async fn from_reqwest(response: reqwest::Response) -> Self {
let status = response.status();
let headers = response.headers().clone();
let url = response.url().clone();
let body = response.bytes().await.unwrap_or_default();
Self {
status,
headers,
body,
url,
}
}
pub fn status(&self) -> StatusCode {
self.status
}
pub fn is_success(&self) -> bool {
self.status.is_success()
}
pub fn is_client_error(&self) -> bool {
self.status.is_client_error()
}
pub fn is_server_error(&self) -> bool {
self.status.is_server_error()
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn header(&self, name: impl AsRef<str>) -> Option<&str> {
self.headers
.get(name.as_ref())
.and_then(|v| v.to_str().ok())
}
pub fn url(&self) -> &url::Url {
&self.url
}
pub fn bytes(&self) -> &Bytes {
&self.body
}
pub fn into_bytes(self) -> Bytes {
self.body
}
pub fn text(&self) -> Result<String> {
String::from_utf8(self.body.to_vec()).map_err(|e| HttpClientError::Json(e.to_string()))
}
pub fn into_text(self) -> Result<String> {
self.text()
}
pub fn json<T: DeserializeOwned>(&self) -> Result<T> {
serde_json::from_slice(&self.body).map_err(|e| HttpClientError::Json(e.to_string()))
}
pub fn into_json<T: DeserializeOwned>(self) -> Result<T> {
self.json()
}
pub fn content_length(&self) -> Option<u64> {
self.headers
.get(http::header::CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse().ok())
}
pub fn content_type(&self) -> Option<&str> {
self.header("content-type")
}
pub fn error_for_status(self) -> Result<Self> {
if self.status.is_client_error() || self.status.is_server_error() {
let message = self.text().unwrap_or_else(|_| "Unknown error".to_string());
Err(HttpClientError::Response {
status: self.status.as_u16(),
message,
})
} else {
Ok(self)
}
}
}