pinboard_rs/api/
ignore.rs1use async_trait::async_trait;
8use http::{header, Request};
9
10use crate::api::{query, ApiError, AsyncClient, AsyncQuery, Client, Endpoint, Query};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct Ignore<E> {
15 endpoint: E,
16}
17
18pub fn ignore<E>(endpoint: E) -> Ignore<E> {
20 Ignore { endpoint }
21}
22
23impl<E, C> Query<(), C> for Ignore<E>
24where
25 E: Endpoint,
26 C: Client,
27{
28 fn query(&self, client: &C) -> Result<(), ApiError<C::Error>> {
29 let mut url = client.rest_endpoint(&self.endpoint.endpoint())?;
30 self.endpoint.parameters().add_to_url(&mut url);
31
32 let req = Request::builder()
33 .method(self.endpoint.method())
34 .uri(query::url_to_http_uri(url));
35 let (req, data) = if let Some((mime, data)) = self.endpoint.body()? {
36 let req = req.header(header::CONTENT_TYPE, mime);
37 (req, data)
38 } else {
39 (req, Vec::new())
40 };
41 let rsp = client.rest(req, data)?;
42 if !rsp.status().is_success() {
43 let v = serde_json::from_slice(rsp.body())?;
44 return Err(ApiError::from_pinboard(v));
45 }
46
47 Ok(())
48 }
49}
50
51#[async_trait]
52impl<E, C> AsyncQuery<(), C> for Ignore<E>
53where
54 E: Endpoint + Sync,
55 C: AsyncClient + Sync,
56{
57 async fn query_async(&self, client: &C) -> Result<(), ApiError<C::Error>> {
58 let mut url = client.rest_endpoint(&self.endpoint.endpoint())?;
59 self.endpoint.parameters().add_to_url(&mut url);
60
61 let req = Request::builder()
62 .method(self.endpoint.method())
63 .uri(query::url_to_http_uri(url));
64 let (req, data) = if let Some((mime, data)) = self.endpoint.body()? {
65 let req = req.header(header::CONTENT_TYPE, mime);
66 (req, data)
67 } else {
68 (req, Vec::new())
69 };
70 let rsp = client.rest_async(req, data).await?;
71 if !rsp.status().is_success() {
72 let v = serde_json::from_slice(rsp.body())?;
73 return Err(ApiError::from_pinboard(v));
74 }
75
76 Ok(())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use http::StatusCode;
83 use serde_json::json;
84
85 use crate::api::endpoint_prelude::*;
86 use crate::api::{self, ApiError, AsyncQuery, Query};
87 use crate::test::client::{ExpectedUrl, SingleTestClient};
88
89 struct Dummy;
90
91 impl Endpoint for Dummy {
92 fn method(&self) -> Method {
93 Method::GET
94 }
95
96 fn endpoint(&self) -> Cow<'static, str> {
97 "dummy".into()
98 }
99 }
100
101 #[test]
102 fn test_pinboard_non_json_response() {
103 let endpoint = ExpectedUrl::builder().endpoint("dummy").build().unwrap();
104 let client = SingleTestClient::new_raw(endpoint, "not json");
105
106 api::ignore(Dummy).query(&client).unwrap()
107 }
108
109 #[tokio::test]
110 async fn test_pinboard_non_json_response_async() {
111 let endpoint = ExpectedUrl::builder().endpoint("dummy").build().unwrap();
112 let client = SingleTestClient::new_raw(endpoint, "not json");
113
114 api::ignore(Dummy).query_async(&client).await.unwrap()
115 }
116
117 #[test]
118 fn test_pinboard_error_bad_json() {
119 let endpoint = ExpectedUrl::builder()
120 .endpoint("dummy")
121 .status(StatusCode::NOT_FOUND)
122 .build()
123 .unwrap();
124 let client = SingleTestClient::new_raw(endpoint, "");
125
126 let err = api::ignore(Dummy).query(&client).unwrap_err();
127 if let ApiError::Json { source } = err {
128 assert_eq!(
129 format!("{}", source),
130 "EOF while parsing a value at line 1 column 0",
131 );
132 } else {
133 panic!("unexpected error: {}", err);
134 }
135 }
136
137 #[test]
138 fn test_pinboard_error_detection() {
139 let endpoint = ExpectedUrl::builder()
140 .endpoint("dummy")
141 .status(StatusCode::NOT_FOUND)
142 .build()
143 .unwrap();
144 let client = SingleTestClient::new_json(
145 endpoint,
146 &json!({
147 "message": "dummy error message",
148 }),
149 );
150
151 let err = api::ignore(Dummy).query(&client).unwrap_err();
152 if let ApiError::PinboardUnrecognized { obj } = err {
153 assert_eq!(
154 obj.pointer("/message").expect("error message"),
155 "dummy error message"
156 );
157 } else {
158 panic!("unexpected error: {}", err);
159 }
160 }
161
162 #[test]
163 fn test_pinboard_error_detection_legacy() {
164 let endpoint = ExpectedUrl::builder()
165 .endpoint("dummy")
166 .status(StatusCode::NOT_FOUND)
167 .build()
168 .unwrap();
169 let client = SingleTestClient::new_json(
170 endpoint,
171 &json!({
172 "error": "dummy error message",
173 }),
174 );
175
176 let err = api::ignore(Dummy).query(&client).unwrap_err();
177 println!("ERR: <{:?}>", err);
178 if let ApiError::PinboardUnrecognized { obj } = err {
179 assert_eq!(
180 obj.pointer("/error").expect("error message"),
181 "dummy error message"
182 );
183 } else {
184 panic!("unexpected error: {}", err);
185 }
186 }
187
188 #[test]
189 fn test_pinboard_error_detection_unknown() {
190 let endpoint = ExpectedUrl::builder()
191 .endpoint("dummy")
192 .status(StatusCode::NOT_FOUND)
193 .build()
194 .unwrap();
195 let err_obj = json!({
196 "bogus": "dummy error message",
197 });
198 let client = SingleTestClient::new_json(endpoint, &err_obj);
199
200 let err = api::ignore(Dummy).query(&client).unwrap_err();
201 if let ApiError::PinboardUnrecognized { obj } = err {
202 assert_eq!(obj, err_obj);
203 } else {
204 panic!("unexpected error: {}", err);
205 }
206 }
207}