rust_fetch/network_error.rs
1use std::{fmt::Display, net::SocketAddr};
2
3use bytes::Bytes;
4use reqwest::{Response, StatusCode};
5use thiserror::Error;
6
7/// Represents any non-200 HTTP status code
8///
9/// # Example
10/// ```rust
11/// use httpmock::prelude::*;
12/// use rust_fetch::Fetch;
13///
14/// #[tokio::main]
15/// async fn main() {
16/// let server = MockServer::start();
17/// let fetch = Fetch::new(&server.base_url(), None).unwrap();
18///
19/// server.mock(|when, then| {
20/// when.path("/test").method(GET);
21/// then.status(400);
22/// });
23///
24/// let response = fetch.get::<()>("/test", None).await;
25///
26/// if let Err(rust_fetch::FetchError::NetworkError(ref err)) = response {
27/// assert_eq!(400, err.status_code);
28/// assert_eq!(Some(*server.address()), err.origin_address);
29/// assert_eq!(false, err.raw_body.is_none());
30/// } else {
31/// panic!("Result was not an instance of NetworkError");
32/// }
33///
34/// assert!(response.is_err());
35/// }
36/// ```
37#[derive(Error, Debug)]
38pub struct NetworkError {
39 pub status_code: StatusCode,
40 pub origin_address: Option<SocketAddr>,
41 pub raw_body: Option<Bytes>,
42}
43
44impl Display for NetworkError {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 let body = self
47 .raw_body
48 .as_ref()
49 .map(|val| String::from_utf8(val.to_owned().to_vec()).ok())
50 .unwrap_or_default()
51 .unwrap_or_default();
52
53 write!(
54 f,
55 "Error -- Status: {}, Origin: {}, Body: {}",
56 self.status_code,
57 self.origin_address
58 .map(|socket| socket.to_string())
59 .unwrap_or_default(),
60 body
61 )
62 }
63}
64
65impl NetworkError {
66 pub async fn new(response: Response) -> Self {
67 Self {
68 status_code: response.status(),
69 origin_address: response.remote_addr(),
70 raw_body: response.bytes().await.ok(),
71 }
72 }
73}