mirror of https://github.com/MingweiSamuel/Riven
Add headers and response body to RiotApiError; remove Reqwest Response reference
parent
fb0030e754
commit
d5494ba442
34
src/error.rs
34
src/error.rs
|
@ -4,7 +4,7 @@ use std::fmt;
|
|||
/// Re-exported `reqwest` types.
|
||||
pub mod reqwest {
|
||||
pub use reqwest::{
|
||||
Error, Response, StatusCode, Url
|
||||
Error, Response, StatusCode, Url, header::HeaderMap
|
||||
};
|
||||
}
|
||||
use ::reqwest::*;
|
||||
|
@ -20,16 +20,24 @@ pub type Result<T> = std::result::Result<T, RiotApiError>;
|
|||
pub struct RiotApiError {
|
||||
reqwest_error: Error,
|
||||
retries: u8,
|
||||
response: Option<Response>,
|
||||
headers: Option<header::HeaderMap>,
|
||||
status_code: Option<StatusCode>,
|
||||
response_body: Option<String>,
|
||||
}
|
||||
impl RiotApiError {
|
||||
pub(crate) fn new(reqwest_error: Error, retries: u8, response: Option<Response>, status_code: Option<StatusCode>) -> Self {
|
||||
pub(crate) fn new(
|
||||
reqwest_error: Error,
|
||||
retries: u8,
|
||||
headers: Option<header::HeaderMap>,
|
||||
status_code: Option<StatusCode>,
|
||||
response_body: Option<String>
|
||||
) -> Self {
|
||||
Self {
|
||||
reqwest_error: reqwest_error,
|
||||
retries: retries,
|
||||
response: response,
|
||||
headers: headers,
|
||||
status_code: status_code,
|
||||
response_body: response_body,
|
||||
}
|
||||
}
|
||||
/// The reqwest::Error for the final failed request.
|
||||
|
@ -40,18 +48,24 @@ impl RiotApiError {
|
|||
pub fn retries(&self) -> u8 {
|
||||
self.retries
|
||||
}
|
||||
/// The failed response.
|
||||
/// `Some(reqwest::Response)` if the request was sent and failed.
|
||||
/// `None` if the request was not sent, OR if parsing the response JSON failed.
|
||||
pub fn response(&self) -> Option<&Response> {
|
||||
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
|
||||
}
|
||||
/// The failed response's headers.
|
||||
/// `Some(reqwest::header::HeaderMap)` if the request was sent and failed.
|
||||
/// `None` if the request was not sent.
|
||||
pub fn headers(&self) -> Option<header::HeaderMap> {
|
||||
self.headers.clone()
|
||||
}
|
||||
/// The failed response's body (as a copy).
|
||||
/// `Some(String)` if the request was sent and failed.
|
||||
/// `None` if the request was not sent.
|
||||
pub fn response_body(&self) -> Option<String> {
|
||||
self.response_body.clone()
|
||||
}
|
||||
}
|
||||
impl fmt::Display for RiotApiError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
@ -86,20 +86,22 @@ impl RegionalRequester {
|
|||
.header(Self::RIOT_KEY_HEADER, &*config.api_key)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| RiotApiError::new(e, retries, None, None))?;
|
||||
.map_err(|e| RiotApiError::new(e, retries, None, None, None))?;
|
||||
|
||||
// Maybe update rate limits (based on response headers).
|
||||
self.app_rate_limit.on_response(&config, &response);
|
||||
method_rate_limit.on_response(&config, &response);
|
||||
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
|
||||
// Handle normal success / failure cases.
|
||||
match response.error_for_status_ref() {
|
||||
// Success.
|
||||
Ok(_response) => {
|
||||
log::trace!("Response {} (retried {} times), parsed result.", status, retries);
|
||||
let value = response.json::<T>().await;
|
||||
break value.map_err(|e| RiotApiError::new(e, retries, None, Some(status)));
|
||||
break value.map_err(|e| RiotApiError::new(e, retries, Some(headers), Some(status), None));
|
||||
},
|
||||
// Failure, may or may not be retryable.
|
||||
Err(err) => {
|
||||
|
@ -110,7 +112,23 @@ impl RegionalRequester {
|
|||
&& !status.is_server_error())
|
||||
{
|
||||
log::debug!("Response {} (retried {} times), returning.", status, retries);
|
||||
break Err(RiotApiError::new(err, retries, Some(response), Some(status)));
|
||||
|
||||
// Extract the response body from bytes into a String,
|
||||
// accounting for potentially non-utf-8 characters.
|
||||
let content = response.bytes().await;
|
||||
|
||||
break match content {
|
||||
Ok(bytes) => {
|
||||
let body = String::from_utf8_lossy(&bytes).into_owned();
|
||||
|
||||
Err(RiotApiError::new(err, retries, Some(headers), Some(status), Some(body)))
|
||||
}
|
||||
Err(_inner_err) => {
|
||||
// Throw the inner error away and ignore response body parsing
|
||||
|
||||
Err(RiotApiError::new(err, retries, Some(headers), Some(status), None))
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("Response {} (retried {} times), retrying.", status, retries);
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue