Rust
reqwest
An ergonomic, batteries-included HTTP Client for Rust.
参考
GitHub REST API
このページでは全体を通してGitHub REST APIを例に使用します。試しにcurlでAPIを叩いてみます。
対象リポジトリはhttps://github.com/rust-lang/rust
curl -L \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2026-03-10" \
https://api.github.com/repos/rust-lang/rust{
"id": 724712,
"node_id": "MDEwOlJlcG9zaXRvcnk3MjQ3MTI=",
"name": "rust",
"full_name": "rust-lang/rust",
"private": false,
"owner": {
"login": "rust-lang",
"id": 5430905,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=",
"avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/rust-lang",
"html_url": "https://github.com/rust-lang",
"followers_url": "https://api.github.com/users/rust-lang/followers",
"following_url": "https://api.github.com/users/rust-lang/following{/other_user}",
"gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}",
"starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions",
"organizations_url": "https://api.github.com/users/rust-lang/orgs",
"repos_url": "https://api.github.com/users/rust-lang/repos",
"events_url": "https://api.github.com/users/rust-lang/events{/privacy}",
"received_events_url": "https://api.github.com/users/rust-lang/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/rust-lang/rust",
"description": "Empowering everyone to build reliable and efficient software.",
"fork": false,
"url": "https://api.github.com/repos/rust-lang/rust",
"forks_url": "https://api.github.com/repos/rust-lang/rust/forks",
"keys_url": "https://api.github.com/repos/rust-lang/rust/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/rust-lang/rust/teams",
"hooks_url": "https://api.github.com/repos/rust-lang/rust/hooks",
"issue_events_url": "https://api.github.com/repos/rust-lang/rust/issues/events{/number}",
"events_url": "https://api.github.com/repos/rust-lang/rust/events",
"assignees_url": "https://api.github.com/repos/rust-lang/rust/assignees{/user}",
"branches_url": "https://api.github.com/repos/rust-lang/rust/branches{/branch}",
"tags_url": "https://api.github.com/repos/rust-lang/rust/tags",
"blobs_url": "https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/rust-lang/rust/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/rust-lang/rust/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/rust-lang/rust/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/rust-lang/rust/statuses/{sha}",
"languages_url": "https://api.github.com/repos/rust-lang/rust/languages",
"stargazers_url": "https://api.github.com/repos/rust-lang/rust/stargazers",
"contributors_url": "https://api.github.com/repos/rust-lang/rust/contributors",
"subscribers_url": "https://api.github.com/repos/rust-lang/rust/subscribers",
"subscription_url": "https://api.github.com/repos/rust-lang/rust/subscription",
"commits_url": "https://api.github.com/repos/rust-lang/rust/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/rust-lang/rust/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/rust-lang/rust/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/rust-lang/rust/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/rust-lang/rust/contents/{+path}",
"compare_url": "https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/rust-lang/rust/merges",
"archive_url": "https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/rust-lang/rust/downloads",
"issues_url": "https://api.github.com/repos/rust-lang/rust/issues{/number}",
"pulls_url": "https://api.github.com/repos/rust-lang/rust/pulls{/number}",
"milestones_url": "https://api.github.com/repos/rust-lang/rust/milestones{/number}",
"notifications_url": "https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/rust-lang/rust/labels{/name}",
"releases_url": "https://api.github.com/repos/rust-lang/rust/releases{/id}",
"deployments_url": "https://api.github.com/repos/rust-lang/rust/deployments",
"created_at": "2010-06-16T20:39:03Z",
"updated_at": "2026-06-07T15:17:38Z",
"pushed_at": "2026-06-07T15:02:18Z",
"git_url": "git://github.com/rust-lang/rust.git",
"ssh_url": "[email protected]:rust-lang/rust.git",
"clone_url": "https://github.com/rust-lang/rust.git",
"svn_url": "https://github.com/rust-lang/rust",
"homepage": "https://www.rust-lang.org",
"size": 914819,
"stargazers_count": 113660,
"watchers_count": 113660,
"language": "Rust",
"has_issues": true,
"has_projects": true,
"has_wiki": false,
"has_pages": false,
"has_discussions": false,
"forks_count": 15054,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 12498,
"license": {
"key": "apache-2.0",
"name": "Apache License 2.0",
"spdx_id": "Apache-2.0",
"url": "https://api.github.com/licenses/apache-2.0",
"node_id": "MDc6TGljZW5zZTI="
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [
"compiler",
"language",
"rust"
],
"visibility": "public",
"forks": 15054,
"open_issues": 12498,
"watchers": 113660,
"default_branch": "main",
"temp_clone_token": null,
"custom_properties": {
},
"organization": {
"login": "rust-lang",
"id": 5430905,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzA5MDU=",
"avatar_url": "https://avatars.githubusercontent.com/u/5430905?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/rust-lang",
"html_url": "https://github.com/rust-lang",
"followers_url": "https://api.github.com/users/rust-lang/followers",
"following_url": "https://api.github.com/users/rust-lang/following{/other_user}",
"gists_url": "https://api.github.com/users/rust-lang/gists{/gist_id}",
"starred_url": "https://api.github.com/users/rust-lang/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/rust-lang/subscriptions",
"organizations_url": "https://api.github.com/users/rust-lang/orgs",
"repos_url": "https://api.github.com/users/rust-lang/repos",
"events_url": "https://api.github.com/users/rust-lang/events{/privacy}",
"received_events_url": "https://api.github.com/users/rust-lang/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"network_count": 15054,
"subscribers_count": 1577
}
All API requests must include a valid User-Agent header. By default, curl sends a valid User-Agent header.
User-Agentヘッダーが必須である点に注意します。curlは勝手にUser-Agentヘッダーを付けてくれますが、以下のRustコードのように、そうではない場合は明示的に追加します。
プロジェクト作成
cargo new example
cd example
# tree
# .
# ├── Cargo.toml
# └── src
# └── main.rscargo add anyhow
cargo add serde --features derive
cargo add tokio --features macros,rt-multi-thread
cargo add reqwest --features json例1
use anyhow::Result;
use reqwest::header::USER_AGENT;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Repository {
full_name: String,
stargazers_count: u64,
forks_count: u64,
language: Option<String>,
}
#[tokio::main]
async fn main() -> Result<()> {
let repo = reqwest::Client::new()
.get("https://api.github.com/repos/rust-lang/rust")
.header(USER_AGENT, "example-app")
.send()
.await?
.error_for_status()?
.json::<Repository>()
.await?;
println!("name: {}", repo.full_name);
println!("stars: {}", repo.stargazers_count);
println!("forks: {}", repo.forks_count);
println!(
"language: {}",
repo.language.as_deref().unwrap_or("(unknown)")
);
Ok(())
}cargo runname: rust-lang/rust
stars: 113660
forks: 15054
language: Rust"language": nullを返すリポジトリもあるので(e.g. trueroad/HaranoAjiFonts)、Repository構造体ではlanguageをOptionにしています。
例2
User-Agentやtimeoutを設定したreqwest::Clientを再利用できる形にしています。
use anyhow::{Context, Result};
use reqwest::{
Client,
header::{ACCEPT, HeaderMap, HeaderValue, USER_AGENT},
};
use serde::Deserialize;
use std::{env, time::Duration};
#[derive(Debug, Deserialize)]
struct Repository {
full_name: String,
stargazers_count: u64,
forks_count: u64,
language: Option<String>,
}
fn build_http_client() -> Result<Client> {
let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, HeaderValue::from_static("example-app"));
headers.insert(
ACCEPT,
HeaderValue::from_static("application/vnd.github+json"),
);
let client = Client::builder()
.default_headers(headers)
.timeout(Duration::from_secs(10))
.build()
.context("failed to build reqwest client")?;
Ok(client)
}
async fn fetch_repository(client: &Client, owner: &str, repo: &str) -> Result<Repository> {
let url = format!("https://api.github.com/repos/{owner}/{repo}");
let repository = client
.get(&url)
.send()
.await
.with_context(|| format!("failed to send request: {url}"))?
.error_for_status()
.with_context(|| format!("GitHub API returned error status: {url}"))?
.json::<Repository>()
.await
.with_context(|| format!("failed to parse repository JSON: {url}"))?;
Ok(repository)
}
#[tokio::main]
async fn main() -> Result<()> {
let owner = env::args()
.nth(1)
.unwrap_or_else(|| "rust-lang".to_string());
let repo = env::args().nth(2).unwrap_or_else(|| "rust".to_string());
let client = build_http_client()?;
let repo = fetch_repository(&client, &owner, &repo).await?;
println!("name: {}", repo.full_name);
println!("stars: {}", repo.stargazers_count);
println!("forks: {}", repo.forks_count);
println!(
"language: {}",
repo.language.as_deref().unwrap_or("(unknown)")
);
Ok(())
}# rust-lang/rust
cargo run
# trueroad/HaranoAjiFonts
cargo run -- trueroad HaranoAjiFontsname: trueroad/HaranoAjiFonts
stars: 166
forks: 3
language: (unknown)Last updated on