From 0ee5806534217f27e646f52a8c5460dd87ee133d Mon Sep 17 00:00:00 2001 From: Klaus Purer Date: Sat, 10 Feb 2018 19:21:12 +0100 Subject: [PATCH] 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 --- src/lib.rs | 73 ++++++++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 731a775..eaaf837 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ use std::ops; use json::Error as SerdeError; use reqwest::Error as HttpError; -use reqwest::{Client, StatusCode}; +use reqwest::{Client, Response, StatusCode}; use reqwest::header::{Authorization, Bearer, Headers}; use entities::prelude::*; @@ -74,20 +74,11 @@ macro_rules! methods { fn $method serde::Deserialize<'de>>(&self, url: String) -> Result { - use std::io::Read; - - let mut response = self.client.$method(&url) + let response = self.client.$method(&url) .headers(self.headers.clone()) .send()?; - let mut vec = Vec::new(); - response.read_to_end(&mut vec)?; - - if let Ok(t) = json::from_slice(&vec) { - Ok(t) - } else { - Err(Error::Api(json::from_slice(&vec)?)) - } + json_convert_response(response) } )+ }; @@ -103,7 +94,6 @@ macro_rules! route { #[doc = "# Errors"] /// If `access_token` is not set. pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> { - use std::io::Read; use reqwest::multipart::Form; let form_data = Form::new() @@ -111,7 +101,7 @@ macro_rules! route { .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()) .multipart(form_data) .send()?; @@ -124,15 +114,7 @@ macro_rules! route { return Err(Error::Server(status)); } - let mut vec = Vec::new(); - - response.read_to_end(&mut vec)?; - - - match json::from_slice::<$ret>(&vec) { - Ok(res) => Ok(res), - Err(_) => Err(Error::Api(json::from_slice(&vec)?)), - } + json_convert_response(response) } route!{$($rest)*} @@ -146,7 +128,6 @@ macro_rules! route { #[doc = "# Errors"] /// If `access_token` is not set. pub fn $name(&self, $($param: $typ,)*) -> Result<$ret> { - use std::io::Read; 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()) .json(&form_data) .send()?; @@ -167,14 +148,7 @@ macro_rules! route { return Err(Error::Server(status)); } - let mut vec = Vec::new(); - - response.read_to_end(&mut vec)?; - - match json::from_slice(&vec) { - Ok(res) => Ok(res), - Err(_) => Err(Error::Api(json::from_slice(&vec)?)), - } + json_convert_response(response) } route!{$($rest)*} @@ -392,21 +366,13 @@ impl Mastodon { /// Post a new status to the account. pub fn new_status(&self, status: StatusBuilder) -> Result { - 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()) .json(&status) .send()?; - let mut vec = Vec::new(); - response.read_to_end(&mut vec)?; - - if let Ok(t) = json::from_slice(&vec) { - Ok(t) - } else { - Err(Error::Api(json::from_slice(&vec)?)) - } + json_convert_response(response) } /// Get the federated timeline for the instance. @@ -526,3 +492,24 @@ from! { HttpError, Http, IoError, Io, } + +// Convert the HTTP response body from JSON. Pass up deserialization errors +// transparently. +fn json_convert_response serde::Deserialize<'de>>(mut response: Response) -> Result { + 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()) + }, + } +}