fix(errors): Directly pass up Serde errors for easier debugging (#16)
* fix(errors): Directly pass up Serde errors for easier debugging * refactor(errors): Also check for API errors * tests(errors): Add test case * tests(upload): Ignore integration test with real Mastodon connection per default * fix(tests): Fix error assertion after change of field ordering * refactor(json): Create a shared function for response JSON converting
This commit is contained in:
+30
-43
@@ -58,7 +58,7 @@ use std::ops;
|
|||||||
|
|
||||||
use json::Error as SerdeError;
|
use json::Error as SerdeError;
|
||||||
use reqwest::Error as HttpError;
|
use reqwest::Error as HttpError;
|
||||||
use reqwest::{Client, StatusCode};
|
use reqwest::{Client, Response, StatusCode};
|
||||||
use reqwest::header::{Authorization, Bearer, Headers};
|
use reqwest::header::{Authorization, Bearer, Headers};
|
||||||
|
|
||||||
use entities::prelude::*;
|
use entities::prelude::*;
|
||||||
@@ -74,20 +74,11 @@ macro_rules! methods {
|
|||||||
fn $method<T: for<'de> serde::Deserialize<'de>>(&self, url: String)
|
fn $method<T: for<'de> serde::Deserialize<'de>>(&self, url: String)
|
||||||
-> Result<T>
|
-> Result<T>
|
||||||
{
|
{
|
||||||
use std::io::Read;
|
let response = self.client.$method(&url)
|
||||||
|
|
||||||
let mut response = self.client.$method(&url)
|
|
||||||
.headers(self.headers.clone())
|
.headers(self.headers.clone())
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
json_convert_response(response)
|
||||||
response.read_to_end(&mut vec)?;
|
|
||||||
|
|
||||||
if let Ok(t) = json::from_slice(&vec) {
|
|
||||||
Ok(t)
|
|
||||||
} else {
|
|
||||||
Err(Error::Api(json::from_slice(&vec)?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
};
|
};
|
||||||
@@ -103,7 +94,6 @@ macro_rules! route {
|
|||||||
#[doc = "# Errors"]
|
#[doc = "# Errors"]
|
||||||
/// If `access_token` is not set.
|
/// If `access_token` is not set.
|
||||||
pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
|
pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
|
||||||
use std::io::Read;
|
|
||||||
use reqwest::multipart::Form;
|
use reqwest::multipart::Form;
|
||||||
|
|
||||||
let form_data = Form::new()
|
let form_data = Form::new()
|
||||||
@@ -111,7 +101,7 @@ macro_rules! route {
|
|||||||
.file(stringify!($param), $param.as_ref())?
|
.file(stringify!($param), $param.as_ref())?
|
||||||
)*;
|
)*;
|
||||||
|
|
||||||
let mut response = self.client.post(&self.route(concat!("/api/v1/", $url)))
|
let response = self.client.post(&self.route(concat!("/api/v1/", $url)))
|
||||||
.headers(self.headers.clone())
|
.headers(self.headers.clone())
|
||||||
.multipart(form_data)
|
.multipart(form_data)
|
||||||
.send()?;
|
.send()?;
|
||||||
@@ -124,15 +114,7 @@ macro_rules! route {
|
|||||||
return Err(Error::Server(status));
|
return Err(Error::Server(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
json_convert_response(response)
|
||||||
|
|
||||||
response.read_to_end(&mut vec)?;
|
|
||||||
|
|
||||||
|
|
||||||
match json::from_slice::<$ret>(&vec) {
|
|
||||||
Ok(res) => Ok(res),
|
|
||||||
Err(_) => Err(Error::Api(json::from_slice(&vec)?)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route!{$($rest)*}
|
route!{$($rest)*}
|
||||||
@@ -146,7 +128,6 @@ macro_rules! route {
|
|||||||
#[doc = "# Errors"]
|
#[doc = "# Errors"]
|
||||||
/// If `access_token` is not set.
|
/// If `access_token` is not set.
|
||||||
pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
|
pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
let form_data = json!({
|
let form_data = json!({
|
||||||
$(
|
$(
|
||||||
@@ -154,7 +135,7 @@ macro_rules! route {
|
|||||||
)*
|
)*
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = self.client.post(&self.route(concat!("/api/v1/", $url)))
|
let response = self.client.post(&self.route(concat!("/api/v1/", $url)))
|
||||||
.headers(self.headers.clone())
|
.headers(self.headers.clone())
|
||||||
.json(&form_data)
|
.json(&form_data)
|
||||||
.send()?;
|
.send()?;
|
||||||
@@ -167,14 +148,7 @@ macro_rules! route {
|
|||||||
return Err(Error::Server(status));
|
return Err(Error::Server(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
json_convert_response(response)
|
||||||
|
|
||||||
response.read_to_end(&mut vec)?;
|
|
||||||
|
|
||||||
match json::from_slice(&vec) {
|
|
||||||
Ok(res) => Ok(res),
|
|
||||||
Err(_) => Err(Error::Api(json::from_slice(&vec)?)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route!{$($rest)*}
|
route!{$($rest)*}
|
||||||
@@ -392,21 +366,13 @@ impl Mastodon {
|
|||||||
|
|
||||||
/// Post a new status to the account.
|
/// Post a new status to the account.
|
||||||
pub fn new_status(&self, status: StatusBuilder) -> Result<Status> {
|
pub fn new_status(&self, status: StatusBuilder) -> Result<Status> {
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
let mut response = self.client.post(&self.route("/api/v1/statuses"))
|
let response = self.client.post(&self.route("/api/v1/statuses"))
|
||||||
.headers(self.headers.clone())
|
.headers(self.headers.clone())
|
||||||
.json(&status)
|
.json(&status)
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
json_convert_response(response)
|
||||||
response.read_to_end(&mut vec)?;
|
|
||||||
|
|
||||||
if let Ok(t) = json::from_slice(&vec) {
|
|
||||||
Ok(t)
|
|
||||||
} else {
|
|
||||||
Err(Error::Api(json::from_slice(&vec)?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the federated timeline for the instance.
|
/// Get the federated timeline for the instance.
|
||||||
@@ -526,3 +492,24 @@ from! {
|
|||||||
HttpError, Http,
|
HttpError, Http,
|
||||||
IoError, Io,
|
IoError, Io,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the HTTP response body from JSON. Pass up deserialization errors
|
||||||
|
// transparently.
|
||||||
|
fn json_convert_response<T: for<'de> serde::Deserialize<'de>>(mut response: Response) -> Result<T> {
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
response.read_to_end(&mut vec)?;
|
||||||
|
|
||||||
|
match json::from_slice(&vec) {
|
||||||
|
Ok(t) => Ok(t),
|
||||||
|
// If deserializing into the desired type fails try again to
|
||||||
|
// see if this is an error response.
|
||||||
|
Err(e) => {
|
||||||
|
if let Ok(error) = json::from_slice(&vec) {
|
||||||
|
return Err(Error::Api(error));
|
||||||
|
}
|
||||||
|
Err(e.into())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user