
API 設計原理:從理論到實踐
rustfs/rustfs 是一款以 Rust 語言編寫的文件系統抽象層庫,目的是讓開發者能夠通過統一的 API 訪問本地文件、Amazon S3、Google Cloud Storage、IPFS 等后端存儲。核心設計思路如下:
FileSystem
、File
、DirEntry
等一系列 trait,所有后端實現都必須遵循。async
/await
和 Tokio,支持高并發場景。在你的 Cargo.toml
中引入:
[dependencies]
rustfs = { git = "https://github.com/rustfs/rustfs.git", branch = "main" }
tokio = { version = "1", features = ["full"] }
> 同時你可能還需要為具體后端添加對應的 feature,例如:rustfs-s3
、rustfs-gcs
等。
以下示例展示了如何使用 rustfs
訪問本地文件和 S3 存儲,并列出根目錄下的所有文件:
use rustfs::{FileSystem, LocalFs, S3Fs};
use std::sync::Arc;
#[tokio::main]
async fn main() - > anyhow::Result < () < {
// 本地文件系統
let local = Arc::new(LocalFs::new("/path/to/dir"));
// S3 文件系統
let s3 = Arc::new(S3Fs::new("my-bucket", "us-east-1")?);
// 列出本地文件
println!("Local files:");
for entry in local.read_dir("/").await? {
println!(" - {}", entry.path());
}
// 列出 S3 對象
println!("\nS3 objects:");
for entry in s3.read_dir("/").await? {
println!(" - {}", entry.path());
}
Ok(())
}
pocketbase/pocketbase 是一個用 Go 語言編寫的開源 BaaS(Backend-as-a-Service)項目,目標是讓前端或移動端開發者能夠“零運維”快速擁有一套完整的后端,包括:
下載預編譯二進制包,或自行編譯:
# 下載并賦予執行權限
curl -L https://github.com/pocketbase/pocketbase/releases/download/v0.15.1/pocketbase_0.15.1_linux_amd64.zip -o pb.zip
unzip pb.zip && chmod +x pocketbase
# 初次運行將創建數據目錄
./pocketbase serve
在瀏覽器訪問 http://127.0.0.1:8090/_/
,即可看到 Admin 控制臺,初始化管理員賬號后便可創建數據模型與用戶。
tasks
。添加字段:
title
(text)completed
(bool)在代碼層面,通過 HTTP 請求操作數據,示例(Node.js):
import fetch from 'node-fetch';
// 假設已通過登錄接口獲取到 token
const TOKEN = 'YOUR_JWT_TOKEN';
async function createTask(title) {
const res = await fetch('http://127.0.0.1:8090/api/collections/tasks/records', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${TOKEN}
,
},
body: JSON.stringify({ title, completed: false }),
});
return res.json();
}
createTask('學習 Rust').then(console.log);
smallcloudai/refact 是一款面向機器學習工程師和研究人員的模型重構與優化工具。它支持:
# Python 環境安裝
pip install refact
示例:對 PyTorch 模型進行 8-bit 量化并導出:
from refact import Quantizer
# 加載模型
model = torch.load('model.pt')
# 量化
quantizer = Quantizer(model, backend='pytorch', precision=8)
qmodel = quantizer.quantize()
# 保存量化后模型
qmodel.save('model_quantized.pt')
更多高級用法請參考官方文檔。
為了幫助大家更好地理解如何借助 Rust 與 GitHub API 快速構建實用工具,下面以 rustfs 社區推薦方式引用視頻中的示例,分步驟帶你用 Rust + Tokio 構建一個命令行程序,從指定倉庫批量獲取最高贊的 Issues。
正如視頻開頭所述,教學最好的方式就是“build cool stuff”。本示例將創建一個 CLI 工具,核心功能:
該示例分兩部分,第一部分實現基礎功能,第二部分引入并發與優化。
cargo new gh_top_issues
cd gh_top_issues
Cargo.toml
中添加依賴:
[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
dotenv = "0.15"
futures = "0.3"
anyhow = "1.0"
.env
中的 GitHub TokenBoxFuture
在項目根目錄創建 .env
,寫入:
GITHUB_TOKEN=your_personal_access_token_here
根據 GitHub REST API 文檔,我們關心的字段有:
Issue 列表接口 GET /repos/{owner}/{repo}/issues
number
(Issue 編號)title
(標題)pull_request
(可選,若存在則為 PR)Reactions 接口 GET /repos/{owner}/{repo}/issues/{issue_number}/reactions
content
(例如 "+1"
表示 ??)user.login
(用戶名)Rust 代碼:
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Issue {
number: u64,
title: String,
#[serde(rename = "pull_request")]
pr: Option < serde_json::Value > ,
}
#[derive(Debug, Serialize, Deserialize)]
struct IssueReaction {
content: String,
user: User,
}
#[derive(Debug, Serialize, Deserialize)]
struct User {
login: String,
}
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, USER_AGENT, ACCEPT};
use std::env;
async fn get_issues(owner: &str, repo: &str, page: u32) - > anyhow::Result < Vec < Issue > > {
let token = env::var("GITHUB_TOKEN")?;
let url = format!(
"https://api.github.com/repos/{}/{}/issues?per_page=100&page={}",
owner, repo, page
);
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, format!("Bearer {}", token).parse()?);
headers.insert(USER_AGENT, HeaderValue::from_static("rust-cli"));
headers.insert(ACCEPT, HeaderValue::from_static("application/vnd.github.v3+json"));
let resp = reqwest::Client::new()
.get(&url)
.headers(headers)
.send()
.await?;
if !resp.status().is_success() {
return Ok(vec![]);
}
let issues: Vec < Issue > = resp.json().await?;
// 過濾掉 PR
Ok(issues.into_iter().filter(|i| i.pr.is_none()).collect())
}
GitHub API 每頁最多返回 100 條,通過響應頭中的 Link
字段判斷是否有下一頁:
fn extract_next_link(headers: &HeaderMap) - > Option < String > {
headers
.get("link")
.and_then(|v| v.to_str().ok())
.and_then(|s| {
s.split(',')
.find(|part| part.contains("rel=\"next\""))
})
.map(|part| {
part.split(';').next().unwrap()
.trim()[1..part.find(' >').unwrap()].to_string()
})
}
封裝遞歸調用為 BoxFuture
,不斷獲取下一頁,直至無 next
link。
async fn get_issue_reactions(owner: &str, repo: &str, issue_number: u64) - > anyhow::Result < usize > {
let token = env::var("GITHUB_TOKEN")?;
let url = format!(
"https://api.github.com/repos/{}/{}/issues/{}/reactions",
owner, repo, issue_number
);
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, format!("Bearer {}", token).parse()?);
headers.insert(USER_AGENT, HeaderValue::from_static("rust-cli"));
headers.insert(ACCEPT, HeaderValue::from_static("application/vnd.github.squirrel-girl-preview"));
let resp = reqwest::Client::new()
.get(&url)
.headers(headers)
.send()
.await?;
let reactions: Vec < IssueReaction > = resp.json().await?;
Ok(reactions.into_iter().filter(|r| r.content == "+1").count())
}
最終在 main
中:
get_issue_reactions
(下一集內容)如視頻所言,下一步將在 Tokio 中使用 futures::stream::FuturesUnordered
或 tokio::task::spawn
,將對每個 Issue 的 Reaction 請求并發化,大幅提升整體速度。
既然我們掌握了上述原理,不妨將這種“基于 API 構建 CLI 工具”的思路,遷移到 rustfs/rustfs
。例如,可以借助 rustfs
統一接口,實現:
這正是開源項目結合的魅力:一個項目解決存儲,一套工具解決 API 交互,你的業務場景便可以靈活擴展。
2025年7月第2周,rustfs/rustfs
、pocketbase/pocketbase
、smallcloudai/refact
三款熱門倉庫各具特色——前者讓多后端文件操作無縫銜接,后者讓后端即服務觸手可及,后者則為模型重構提供利器。更重要的是,通過以上示例,我們學習了如何使用 Rust 與 GitHub API 打通數據流,快速構建高效 CLI 工具。
希望本文能幫助你:
原文引自YouTube視頻:https://www.youtube.com/watch?v=zzfZ13_Ig78