Adds example of handle a rate-limited API #93

This commit is contained in:
João Bolila 2017-10-14 23:22:04 +01:00 committed by Michał Budzyński
parent 29dacc6267
commit 2d3679b14e
2 changed files with 84 additions and 0 deletions

View file

@ -109,6 +109,7 @@ community. It needs and welcomes help. For details see
| [Check webpage for broken links][ex-check-broken-links] | [![reqwest-badge]][reqwest] [![select-badge]][select] [![url-badge]][url] | [![cat-net-badge]][cat-net] |
| [Extract all unique links from a MediaWiki markup][ex-extract-mediawiki-links] | [![reqwest-badge]][reqwest] [![regex-badge]][regex] | [![cat-net-badge]][cat-net] |
| [Make a partial download with HTTP range headers][ex-progress-with-range] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] |
| [Handle a rate-limited API][ex-handle-rate-limited-api] | [![reqwest-badge]][reqwest] [![hyper-badge]][hyper] | [![cat-net-badge]][cat-net] |
## [Application development](app.html)
@ -263,3 +264,4 @@ community. It needs and welcomes help. For details see
[ex-url-rm-frag]: net.html#ex-url-rm-frag
[ex-urlencoded]: encoding.html#ex-urlencoded
[ex-verify-extract-email]: basics.html#ex-verify-extract-email
[ex-handle-rate-limited-api]: net.html#ex-handle-rate-limited-api

View file

@ -20,6 +20,7 @@
| [Check webpage for broken links][ex-check-broken-links] | [![reqwest-badge]][reqwest] [![select-badge]][select] [![url-badge]][url] | [![cat-net-badge]][cat-net] |
| [Extract all unique links from a MediaWiki markup][ex-extract-mediawiki-links] | [![reqwest-badge]][reqwest] [![regex-badge]][regex] | [![cat-net-badge]][cat-net] |
| [Make a partial download with HTTP range headers][ex-progress-with-range] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] |
| [Handle a rate-limited API][ex-handle-rate-limited-api] | [![reqwest-badge]][reqwest] [![hyper-badge]][hyper] | [![cat-net-badge]][cat-net] |
[ex-url-parse]: #ex-url-parse
<a name="ex-url-parse"/>
@ -1120,6 +1121,85 @@ fn run() -> Result<()> {
# quick_main!(run);
```
[ex-handle-rate-limited-api]: #ex-handle-rate-limited-api
<a name="ex-handle-rate-limited-api"/>
## Handle a rate-limited API
[![reqwest-badge]][reqwest] [![hyper-badge]][hyper] [![cat-net-badge]][cat-net]
This example uses the [GitHub API - Rate limiting], as an example of how to
handle remote server errors. This example uses the [`hyper::header!`] macro
to parse the response header and checks for [`reqwest::StatusCode::Forbidden`].
If the response exceeds the rate limit, the example waits and retries.
```rust,no_run
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate hyper;
extern crate reqwest;
use std::time::{Duration, UNIX_EPOCH};
use std::thread;
use reqwest::StatusCode;
#
# error_chain! {
# errors {
# RateLimitExceded(quote: usize, lease_secs: u64) {
# description("rate limit exceeded")
# display("rate limit exceeded the {} calls, the next call will be allowed within {} seconds", quote, lease_secs)
# }
# }
# foreign_links {
# Io(std::io::Error);
# Time(std::time::SystemTimeError);
# Reqwest(reqwest::Error);
# }
# }
header! { (XRateLimitLimit, "X-RateLimit-Limit") => [usize] }
header! { (XRateLimitRemaining, "X-RateLimit-Remaining") => [usize] }
header! { (XRateLimitReset, "X-RateLimit-Reset") => [u64] }
fn run() -> Result<()> {
let url = "https://api.github.com/users/rust-lang-nursery ";
let client = reqwest::Client::new();
let response = client.get(url).send()?;
let rate_limit = response.headers().get::<XRateLimitLimit>().ok_or(
"response doesn't include the expected X-RateLimit-Limit header",
)?;
let rate_remaining = response.headers().get::<XRateLimitRemaining>().ok_or(
"response doesn't include the expected X-RateLimit-Remaining header",
)?;
let rate_reset_at = response.headers().get::<XRateLimitReset>().ok_or(
"response doesn't include the expected X-RateLimit-Reset header",
)?;
let rate_reset_within = Duration::from_secs(**rate_reset_at) - UNIX_EPOCH.elapsed()?;
if response.status() == StatusCode::Forbidden && **rate_remaining == 0 {
println!("Sleeping for {} seconds.", rate_reset_within.as_secs());
thread::sleep(rate_reset_within);
let _ = run();
}
else {
println!(
"Rate limit is currently {}/{}, the reset of this limit will be within {} seconds.",
**rate_remaining,
**rate_limit,
rate_reset_within.as_secs(),
);
}
Ok(())
}
#
# quick_main!(run);
```
{{#include links.md}}
<!-- API Reference -->
@ -1158,6 +1238,7 @@ fn run() -> Result<()> {
[`reqwest::header::Range`]: https://docs.rs/reqwest/*/reqwest/header/enum.Range.html
[`reqwest::RequestBuilder`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html
[`reqwest::Response`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html
[`reqwest::StatusCode::Forbidden`]: https://docs.rs/reqwest/*/reqwest/enum.StatusCode.html#variant.Forbidden
[`Response::json`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html#method.json
[`Response::url`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html#method.url
[`Selection`]: https://docs.rs/select/*/select/selection/struct.Selection.html
@ -1181,6 +1262,7 @@ fn run() -> Result<()> {
<!-- Other Reference -->
[GitHub API]: https://developer.github.com/v3/auth/
[GitHub API - Rate limiting]: https://developer.github.com/v3/#rate-limiting
[HTTP Basic Auth]: https://tools.ietf.org/html/rfc2617
[HTTP Range RFC7233]: https://tools.ietf.org/html/rfc7233#section-3.1
[MediaWiki link syntax]: https://www.mediawiki.org/wiki/Help:Links