为什么 Rust 是使用 API 的理想选择?
\n\n如果你还以为 Rust 只适用于系统编程和替代 C++,那你就严重落后于现实了。Rust 已经自信地闯入了 Web 开发和后端服务领域。而且不仅仅是闯入,它还在那些重视速度、可靠性和内存安全的细分市场中占据了一席之地。
\n\n但老实说:在 Rust 中使用 API 不仅仅是“拿一个现成的库就用”。它是在语言强大功能与开发便利性之间寻求平衡的艺术。在本文中,我们将分析三种主要方法:REST、GraphQL 和 gRPC。每种方法各有千秋,选择取决于你的具体任务。我们开始吧!
\n\nRust 中的 REST:行之有效的经典方案
\n\nREST 仍然是最流行的 API 风格。它简单、直观,并且几乎受到所有平台的支持。Rust 有几个优秀的框架,但其中的王者是 actix-web。它快速、异步,并且拥有出色的生态系统。
使用 actix-web 编写一个简单的 REST 服务
\n\n让我们创建一个用于管理任务列表 (todo) 的微型服务。我们需要 actix-web、用于序列化的 serde 以及作为异步运行时的 tokio。
// Cargo.toml\n// [dependencies]\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n// serde_json = "1"\n// tokio = { version = "1", features = ["full"] }\n\nuse actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};\nuse serde::{Deserialize, Serialize};\nuse std::sync::Mutex;\n\n#[derive(Serialize, Deserialize, Clone)]\nstruct Task {\n id: u32,\n title: String,\n completed: bool,\n}\n\nstruct AppState {\n tasks: Mutex<Vec<Task>>,\n}\n\n#[get("/tasks")]\nasync fn get_tasks(data: web::Data<AppState>) -> impl Responder {\n let tasks = data.tasks.lock().unwrap();\n HttpResponse::Ok().json(tasks.clone())\n}\n\n#[post("/tasks")]\nasync fn create_task(data: web::Data<AppState>, body: web::Json<Task>) -> impl Responder {\n let mut tasks = data.tasks.lock().unwrap();\n let new_id = tasks.len() as u32 + 1;\n let task = Task {\n id: new_id,\n title: body.title.clone(),\n completed: false,\n };\n tasks.push(task.clone());\n HttpResponse::Created().json(task)\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n let state = web::Data::new(AppState {\n tasks: Mutex::new(vec![]),\n });\n\n HttpServer::new(move || {\n App::new()\n .app_data(state.clone())\n .service(get_tasks)\n .service(create_task)\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\n\n这段代码的美妙之处在于它是内存安全的,并且不需要垃圾回收器。actix-web 利用 Rust 的异步机制,可以在单个线程上每秒处理数千个请求。尝试运行一下——你会惊讶于即使在性能较弱的硬件上它也能如此快速。
什么时候 REST 不是最佳选择?
\n\nREST 非常适合 CRUD 操作,但如果需要灵活地查询数据(例如,嵌套资源),REST 就会开始需要大量的端点。这时,GraphQL 就登场了。
\n\nRust 中的 GraphQL:灵活无痛
\n\nGraphQL 允许客户端精确地请求所需的数据。对于 Rust 来说,最佳选择是 async-graphql。它与 actix-web 紧密集成,并提供了强大的 DSL 来描述模式。
示例:图书管理 API
\n\n假设我们想让客户端能够查询书籍和作者。使用 GraphQL,只需一个模式即可完成。
\n\n// Cargo.toml\n// [dependencies]\n// async-graphql = "7"\n// async-graphql-actix-web = "7"\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n\nuse async_graphql::{Context, EmptyMutatio