Add status code to RiotApiError, handle 204 to return None

users/mingwei/surf
Mingwei Samuel 2020-03-31 12:49:17 -07:00
parent 0459b7d471
commit 81326a5452
2 changed files with 26 additions and 14 deletions

View File

@ -3,8 +3,9 @@ use std::fmt;
/// Re-exported `reqwest` types. /// Re-exported `reqwest` types.
pub mod reqwest { pub mod reqwest {
pub use reqwest::Error; pub use reqwest::{
pub use reqwest::Response; Error, Response, StatusCode, Url
};
} }
use ::reqwest::*; use ::reqwest::*;
@ -20,13 +21,15 @@ pub struct RiotApiError {
reqwest_error: Error, reqwest_error: Error,
retries: u8, retries: u8,
response: Option<Response>, response: Option<Response>,
status_code: Option<StatusCode>,
} }
impl RiotApiError { impl RiotApiError {
pub fn new(reqwest_error: Error, retries: u8, response: Option<Response>) -> Self { pub(crate) fn new(reqwest_error: Error, retries: u8, response: Option<Response>, status_code: Option<StatusCode>) -> Self {
Self { Self {
reqwest_error: reqwest_error, reqwest_error: reqwest_error,
retries: retries, retries: retries,
response: response, response: response,
status_code: status_code,
} }
} }
/// The reqwest::Error for the final failed request. /// The reqwest::Error for the final failed request.
@ -37,11 +40,18 @@ impl RiotApiError {
pub fn retries(&self) -> u8 { pub fn retries(&self) -> u8 {
self.retries self.retries
} }
/// The failed response, if the request was sent and failed. /// The failed response.
/// Will be `None` if JSON parsing failed. /// `Some(reqwest::Response)` if the request was sent and failed.
pub fn response<'a>(&self) -> Option<&Response> { /// `None` if the request was not sent, OR if parsing the response JSON failed.
pub fn response(&self) -> Option<&Response> {
self.response.as_ref() self.response.as_ref()
} }
/// The failed response's HTTP status code.
/// `Some(reqwest::StatusCode)` if the request was sent and failed, OR if parsing the response JSON failed.
/// `None` if the request was not sent.
pub fn status_code(&self) -> Option<StatusCode> {
self.status_code
}
} }
impl fmt::Display for RiotApiError { impl fmt::Display for RiotApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -24,9 +24,11 @@ impl RegionalRequester {
/// Request header name for the Riot API key. /// Request header name for the Riot API key.
const RIOT_KEY_HEADER: &'static str = "X-Riot-Token"; const RIOT_KEY_HEADER: &'static str = "X-Riot-Token";
/// Http status code 404, considered a success but will return None. /// HTTP status codes which are considered a success but will results in `None`.
const NONE_STATUS_CODE: StatusCode = StatusCode::NOT_FOUND; const NONE_STATUS_CODES: [StatusCode; 2] = [
StatusCode::NO_CONTENT, // 204
StatusCode::NOT_FOUND, // 404
];
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -45,8 +47,8 @@ impl RegionalRequester {
method_id, region_platform, path, query).await; method_id, region_platform, path, query).await;
response_result.map(|value| Some(value)) response_result.map(|value| Some(value))
.or_else(|e| { .or_else(|e| {
if let Some(response) = e.response() { if let Some(status) = e.status_code() {
if Self::NONE_STATUS_CODE == response.status() { if Self::NONE_STATUS_CODES.contains(&status) {
return Ok(None); return Ok(None);
}} }}
Err(e) Err(e)
@ -84,7 +86,7 @@ impl RegionalRequester {
.header(Self::RIOT_KEY_HEADER, &*config.api_key) .header(Self::RIOT_KEY_HEADER, &*config.api_key)
.send() .send()
.await .await
.map_err(|e| RiotApiError::new(e, retries, None))?; .map_err(|e| RiotApiError::new(e, retries, None, None))?;
// Maybe update rate limits (based on response headers). // Maybe update rate limits (based on response headers).
self.app_rate_limit.on_response(&config, &response); self.app_rate_limit.on_response(&config, &response);
@ -97,7 +99,7 @@ impl RegionalRequester {
Ok(_response) => { Ok(_response) => {
log::trace!("Response {} (retried {} times), parsed result.", status, retries); log::trace!("Response {} (retried {} times), parsed result.", status, retries);
let value = response.json::<T>().await; let value = response.json::<T>().await;
break value.map_err(|e| RiotApiError::new(e, retries, None)); break value.map_err(|e| RiotApiError::new(e, retries, None, Some(status)));
}, },
// Failure, may or may not be retryable. // Failure, may or may not be retryable.
Err(err) => { Err(err) => {
@ -108,7 +110,7 @@ impl RegionalRequester {
&& !status.is_server_error()) && !status.is_server_error())
{ {
log::debug!("Response {} (retried {} times), returning.", status, retries); log::debug!("Response {} (retried {} times), returning.", status, retries);
break Err(RiotApiError::new(err, retries, Some(response))); break Err(RiotApiError::new(err, retries, Some(response), Some(status)));
} }
log::debug!("Response {} (retried {} times), retrying.", status, retries); log::debug!("Response {} (retried {} times), retrying.", status, retries);
}, },