1use quick_xml::DeError;
2use reqwest::header::{InvalidHeaderName, InvalidHeaderValue};
3use thiserror::Error as ThisError;
4use url::ParseError;
5
6#[derive(Debug, ThisError)]
7pub enum Error {
8 #[error("HTTP request failed: {0}")]
10 Http(#[from] reqwest::Error),
11 #[error("invalid endpoint: {0}")]
13 InvalidEndpoint(String),
14 #[error("invalid header name: {0}")]
16 InvalidHeaderName(#[from] InvalidHeaderName),
17 #[error("invalid header value: {0}")]
19 InvalidHeaderValue(#[from] InvalidHeaderValue),
20 #[error("query serialization failed: {0}")]
22 QuerySerialize(#[from] serde_qs::Error),
23 #[error("unexpected response{}: {body}", content_type_label(content_type.as_deref()))]
25 UnexpectedResponse {
26 content_type: Option<String>,
28 body: String,
30 },
31 #[error("URL parsing failed: {0}")]
33 UrlParse(#[from] ParseError),
34 #[error("XML parsing failed: {0}")]
36 XmlParse(#[from] DeError),
37}
38
39fn content_type_label(content_type: Option<&str>) -> String {
40 match content_type {
41 Some(content_type) => format!(" (content-type: {content_type})"),
42 None => String::new(),
43 }
44}
45
46pub type Result<T> = std::result::Result<T, Error>;
48
49#[cfg(test)]
50mod display_tests {
51 use super::*;
52 use std::error::Error as StdError;
53
54 #[test]
55 fn invalid_endpoint_display() {
56 let e = Error::InvalidEndpoint("bad".into());
57 assert_eq!(e.to_string(), "invalid endpoint: bad");
58 assert!(e.source().is_none());
59 }
60
61 #[test]
62 fn unexpected_response_with_content_type() {
63 let e = Error::UnexpectedResponse {
64 content_type: Some("text/html".into()),
65 body: "<html>".into(),
66 };
67 assert_eq!(
68 e.to_string(),
69 "unexpected response (content-type: text/html): <html>"
70 );
71 assert!(e.source().is_none());
72 }
73
74 #[test]
75 fn unexpected_response_without_content_type() {
76 let e = Error::UnexpectedResponse {
77 content_type: None,
78 body: "oops".into(),
79 };
80 assert_eq!(e.to_string(), "unexpected response: oops");
81 }
82
83 #[test]
84 fn url_parse_wraps_source() {
85 let inner = url::Url::parse("not a url").unwrap_err();
86 let e: Error = inner.into();
87 assert!(e.to_string().starts_with("URL parsing failed: "));
88 assert!(e.source().is_some());
89 }
90}