use bytes::Bytes;
use crate::Error;
pub trait FromHttpResponse {
fn from_http_response(http_response: http::Response<Bytes>) -> Result<Self, Error>
where
Self: Sized;
}
#[cfg(feature = "serde")]
impl<D> FromHttpResponse for D
where
D: serde::de::DeserializeOwned,
{
fn from_http_response(http_response: http::Response<Bytes>) -> Result<Self, Error> {
use snafu::ResultExt as _;
let status = http_response.status();
snafu::ensure!(
status.is_success(),
crate::error::NonSuccessStatusSnafu {
status,
body: http_response.into_body()
}
);
serde_json::from_slice(http_response.body()).context(crate::error::JsonSnafu)
}
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use http::StatusCode;
use serde::Deserialize;
use super::*;
#[derive(Deserialize, Debug, PartialEq)]
struct TestStruct {
id: i32,
name: String,
}
#[tokio::test]
async fn test_from_response_success() {
let response = http::Response::builder()
.status(StatusCode::OK)
.header("content-type", "application/json")
.body(Bytes::from_static(r#"{"id":1,"name":"Test"}"#.as_bytes()))
.expect("valid response required");
let result = TestStruct::from_http_response(response);
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
TestStruct {
id: 1,
name: "Test".to_string()
}
);
}
#[tokio::test]
async fn test_from_response_invalid_json() {
let response = http::Response::builder()
.status(StatusCode::OK)
.header("content-type", "application/json")
.body(Bytes::from_static(r#"{"id":1,"name":"Test"#.as_bytes()))
.expect("valid response required");
let result = TestStruct::from_http_response(response);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::Json { .. }));
}
}