forked from mirror/Riven
1
0
Fork 0

Compare commits

...

5 Commits

Author SHA1 Message Date
Mingwei Samuel 58d693e5ee Bump version 2.0.0-alpha.0 2020-04-19 14:19:31 -07:00
Mingwei Samuel 43d7f607a1 Run autogen, only minor documentation changes 2020-04-19 14:18:24 -07:00
Michal Baumgartner 60317be114 Let Reqwest `text()` convert the Response to a String 2020-04-19 14:15:21 -07:00
Michal Baumgartner 169fa50f63 Add tests for headers and response body 2020-04-19 14:15:21 -07:00
Michal Baumgartner d5494ba442 Add headers and response body to RiotApiError; remove Reqwest Response reference 2020-04-19 14:15:21 -07:00
6 changed files with 73 additions and 17 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "riven" name = "riven"
version = "1.1.0" version = "2.0.0-alpha.0"
authors = ["Mingwei Samuel <mingwei.samuel@gmail.com>"] authors = ["Mingwei Samuel <mingwei.samuel@gmail.com>"]
repository = "https://github.com/MingweiSamuel/Riven" repository = "https://github.com/MingweiSamuel/Riven"
description = "Riot Games API Library" description = "Riot Games API Library"

View File

@ -7,7 +7,7 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/ // http://www.mingweisamuel.com/riotapi-schema/tool/
// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 // Version 64f3c82d132f12808d8eb8f483d1d2182386c432
//! Automatically generated endpoint handles. //! Automatically generated endpoint handles.
@ -261,6 +261,8 @@ pub struct ClashV1<'a> {
} }
impl<'a> ClashV1<'a> { impl<'a> ClashV1<'a> {
/// Get players by summoner ID. /// Get players by summoner ID.
/// ## Implementation Notes
/// This endpoint returns a list of active Clash players for a given summoner ID. If a summoner registers for multiple tournaments at the same time (e.g., Saturday and Sunday) then both registrations would appear in this list.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
/// * `summonerId` /// * `summonerId`

View File

@ -4,7 +4,7 @@ use std::fmt;
/// Re-exported `reqwest` types. /// Re-exported `reqwest` types.
pub mod reqwest { pub mod reqwest {
pub use reqwest::{ pub use reqwest::{
Error, Response, StatusCode, Url Error, Response, StatusCode, Url, header::HeaderMap
}; };
} }
use ::reqwest::*; use ::reqwest::*;
@ -20,16 +20,24 @@ pub type Result<T> = std::result::Result<T, RiotApiError>;
pub struct RiotApiError { pub struct RiotApiError {
reqwest_error: Error, reqwest_error: Error,
retries: u8, retries: u8,
response: Option<Response>, headers: Option<header::HeaderMap>,
status_code: Option<StatusCode>, status_code: Option<StatusCode>,
response_body: Option<String>,
} }
impl RiotApiError { 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 { Self {
reqwest_error: reqwest_error, reqwest_error: reqwest_error,
retries: retries, retries: retries,
response: response, headers: headers,
status_code: status_code, status_code: status_code,
response_body: response_body,
} }
} }
/// The reqwest::Error for the final failed request. /// The reqwest::Error for the final failed request.
@ -40,18 +48,24 @@ impl RiotApiError {
pub fn retries(&self) -> u8 { pub fn retries(&self) -> u8 {
self.retries 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. /// The failed response's HTTP status code.
/// `Some(reqwest::StatusCode)` if the request was sent and failed, OR if parsing the response JSON failed. /// `Some(reqwest::StatusCode)` if the request was sent and failed, OR if parsing the response JSON failed.
/// `None` if the request was not sent. /// `None` if the request was not sent.
pub fn status_code(&self) -> Option<StatusCode> { pub fn status_code(&self) -> Option<StatusCode> {
self.status_code 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 { 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

@ -7,7 +7,7 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/ // http://www.mingweisamuel.com/riotapi-schema/tool/
// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 // Version 64f3c82d132f12808d8eb8f483d1d2182386c432
//! Data transfer structs. //! Data transfer structs.
//! //!
@ -466,7 +466,7 @@ pub mod match_v4 {
pub struct ParticipantIdentity { pub struct ParticipantIdentity {
#[serde(rename = "participantId")] #[serde(rename = "participantId")]
pub participant_id: i32, pub participant_id: i32,
/// Player information. /// Player information not included in the response for custom matches. Custom matches are considered private unless a tournament code was used to create the match.
#[serde(rename = "player")] #[serde(rename = "player")]
pub player: Player, pub player: Player,
} }

View File

@ -86,20 +86,22 @@ 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, None))?; .map_err(|e| RiotApiError::new(e, retries, None, 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);
method_rate_limit.on_response(&config, &response); method_rate_limit.on_response(&config, &response);
let status = response.status(); let status = response.status();
let headers = response.headers().clone();
// Handle normal success / failure cases. // Handle normal success / failure cases.
match response.error_for_status_ref() { match response.error_for_status_ref() {
// Success. // Success.
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, Some(status))); break value.map_err(|e| RiotApiError::new(e, retries, Some(headers), Some(status), None));
}, },
// Failure, may or may not be retryable. // Failure, may or may not be retryable.
Err(err) => { Err(err) => {
@ -110,7 +112,20 @@ 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), Some(status)));
// Extract the response body as a String
let content = response.text().await;
break match content {
Ok(str) => {
Err(RiotApiError::new(err, retries, Some(headers), Some(status), Some(str)))
}
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); log::debug!("Response {} (retried {} times), retrying.", status, retries);
}, },

View File

@ -49,6 +49,31 @@ async_tests!{
} }
Ok(()) Ok(())
}, },
inspecting_response_and_headers_on_error: async {
let sum = RIOT_API.summoner_v4().get_by_puuid(Region::EUW, "clearly not a puuid").await;
match sum {
Ok(_summoner) => rassert!(false, "Should not have succeeded"),
Err(error) => {
match error.headers() {
Some(headers) => {
rassert!(headers.len() > 0, "Invalid headers received: {:?}", error);
rassert!(headers.contains_key("x-app-rate-limit"), "Invalid headers received: {:?}", error);
rassert!(headers.contains_key("x-method-rate-limit"), "Invalid headers received: {:?}", error);
},
None => rassert!(false, "Headers shouldn't be empty"),
}
match error.response_body() {
Some(body) => {
rassert!(body.len() > 0, "Invalid body received: {:?}", error);
},
None => rassert!(false, "The response body shouldn't be empty"),
}
}
};
Ok(())
},
// // TFT tests. // // TFT tests.
// tftleaguev1_getchallengerleague: async { // tftleaguev1_getchallengerleague: async {
// let p = RIOT_API.tft_league_v1().get_challenger_league(Region::EUW); // let p = RIOT_API.tft_league_v1().get_challenger_league(Region::EUW);