use serde::Deserialize;
use std::time::Duration;
use wrest::header;
#[derive(Debug, Deserialize)]
struct Repo {
full_name: String,
description: Option<String>,
stargazers_count: u32,
language: Option<String>,
html_url: String,
}
#[derive(Debug, Deserialize)]
struct User {
login: String,
id: u64,
html_url: String,
#[serde(rename = "type")]
user_type: String,
public_repos: Option<u32>,
}
#[derive(Debug, Deserialize)]
struct SearchResult<T> {
total_count: u32,
items: Vec<T>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut default_headers = wrest::header::HeaderMap::new();
default_headers.insert(header::ACCEPT, "application/vnd.github+json".parse()?);
default_headers.insert(header::USER_AGENT, "wrest-example/0.1".parse()?);
default_headers
.insert("X-GitHub-Api-Version".parse::<header::HeaderName>()?, "2022-11-28".parse()?);
let client = wrest::Client::builder()
.timeout(Duration::from_secs(30))
.default_headers(default_headers)
.retry(
wrest::retry::for_host("api.github.com")
.max_retries_per_request(1)
.classify_fn(|rr| {
if rr.method() == http::Method::GET
&& rr.status() == Some(http::StatusCode::FORBIDDEN)
{
return rr.retryable();
}
rr.success()
}),
)
.build()?;
println!("=== 1. GET /users/{{login}} ===\n");
let user: User = client
.get("https://api.github.com/users/talagrand")
.send()
.await?
.error_for_status()?
.json()
.await?;
println!(" Login: {}", user.login);
println!(" ID: {}", user.id);
println!(" Type: {}", user.user_type);
println!(" Public repos: {:?}", user.public_repos);
println!(" Profile: {}\n", user.html_url);
println!("=== 2. Search repos: top Rust projects by stars ===\n");
let resp = client
.get("https://api.github.com/search/repositories")
.query(&[("q", "language:rust"), ("sort", "stars"), ("order", "desc"), ("per_page", "10")])
.send()
.await?;
println!(" Rate limit: {:?}", resp.headers().get("x-ratelimit-limit"));
println!(" Rate remaining: {:?}", resp.headers().get("x-ratelimit-remaining"));
println!();
let resp = resp.error_for_status()?;
let search: SearchResult<Repo> = resp.json().await?;
println!(" Found {} repos, showing top {}:\n", search.total_count, search.items.len());
for (i, repo) in search.items.iter().enumerate() {
println!(
" {:>2}. {} ⭐ {} -- {}",
i + 1,
repo.full_name,
repo.stargazers_count,
repo.description.as_deref().unwrap_or("(no description)")
);
println!(" lang: {:?} url: {}", repo.language, repo.html_url);
}
println!();
println!("=== 3. List repos for an org (first page) ===\n");
let resp = client
.get("https://api.github.com/orgs/rust-lang/repos")
.query(&[("per_page", "5"), ("sort", "pushed")])
.send()
.await?
.error_for_status()?;
let repos: Vec<Repo> = resp.json().await?;
for repo in &repos {
println!(
" {} -- ⭐ {} -- {}",
repo.full_name,
repo.stargazers_count,
repo.description.as_deref().unwrap_or("(no description)")
);
}
println!();
println!("=== 4. Rate-limit awareness ===\n");
let resp = client
.get("https://api.github.com/rate_limit")
.send()
.await?
.error_for_status()?;
let text = resp.text().await?;
for line in text.lines().take(10) {
println!(" {line}");
}
println!(" ...\n");
println!("Done!");
Ok(())
}