RESTful API #
本节将通过一个完整的示例,演示如何使用Rocket构建RESTful API。
项目结构 #
text
api_project/
├── Cargo.toml
├── Rocket.toml
├── src/
│ ├── main.rs
│ ├── models/
│ │ ├── mod.rs
│ │ └── user.rs
│ ├── routes/
│ │ ├── mod.rs
│ │ └── user.rs
│ ├── db/
│ │ ├── mod.rs
│ │ └── pool.rs
│ └── error.rs
└── migrations/
依赖配置 #
toml
[package]
name = "rocket_api"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = { version = "0.5", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
模型定义 #
rust
use serde::{Serialize, Deserialize};
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: Uuid,
pub username: String,
pub email: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateUser {
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Debug, Deserialize)]
pub struct UpdateUser {
pub username: Option<String>,
pub email: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct UserResponse {
pub id: Uuid,
pub username: String,
pub email: String,
pub created_at: DateTime<Utc>,
}
impl From<User> for UserResponse {
fn from(user: User) -> Self {
Self {
id: user.id,
username: user.username,
email: user.email,
created_at: user.created_at,
}
}
}
错误处理 #
rust
use rocket::http::Status;
use rocket::response::{Responder, Result};
use rocket::serde::json::Json;
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct ErrorResponse {
pub error: String,
pub code: u16,
}
#[derive(Debug)]
pub enum ApiError {
NotFound(String),
BadRequest(String),
Conflict(String),
Internal(String),
}
impl<'r> Responder<'r, 'r> for ApiError {
fn respond_to(self, _req: &'r rocket::Request<'_>) -> Result<'r> {
let (status, message) = match self {
ApiError::NotFound(m) => (Status::NotFound, m),
ApiError::BadRequest(m) => (Status::BadRequest, m),
ApiError::Conflict(m) => (Status::Conflict, m),
ApiError::Internal(m) => (Status::InternalServerError, m),
};
rocket::response::Response::build()
.status(status)
.header(rocket::http::ContentType::JSON)
.sized_body(
serde_json::to_string(&ErrorResponse {
error: message,
code: status.code,
}).unwrap().len(),
std::io::Cursor::new(
serde_json::to_string(&ErrorResponse {
error: String::new(),
code: status.code,
}).unwrap()
)
)
.ok()
}
}
数据库模拟 #
rust
use std::collections::HashMap;
use std::sync::Mutex;
use uuid::Uuid;
use chrono::Utc;
pub struct Db {
users: Mutex<HashMap<Uuid, crate::models::User>>,
}
impl Db {
pub fn new() -> Self {
Self {
users: Mutex::new(HashMap::new()),
}
}
pub fn create(&self, user: crate::models::CreateUser) -> crate::models::User {
let mut users = self.users.lock().unwrap();
let now = Utc::now();
let new_user = crate::models::User {
id: Uuid::new_v4(),
username: user.username,
email: user.email,
created_at: now,
updated_at: now,
};
users.insert(new_user.id, new_user.clone());
new_user
}
pub fn find(&self, id: Uuid) -> Option<crate::models::User> {
self.users.lock().unwrap().get(&id).cloned()
}
pub fn find_all(&self) -> Vec<crate::models::User> {
self.users.lock().unwrap().values().cloned().collect()
}
pub fn update(&self, id: Uuid, update: crate::models::UpdateUser) -> Option<crate::models::User> {
let mut users = self.users.lock().unwrap();
if let Some(user) = users.get_mut(&id) {
if let Some(username) = update.username {
user.username = username;
}
if let Some(email) = update.email {
user.email = email;
}
user.updated_at = Utc::now();
return Some(user.clone());
}
None
}
pub fn delete(&self, id: Uuid) -> bool {
self.users.lock().unwrap().remove(&id).is_some()
}
}
路由实现 #
rust
use rocket::serde::json::Json;
use rocket::State;
use rocket::http::Status;
use crate::models::{CreateUser, UpdateUser, UserResponse};
use crate::db::Db;
use crate::error::ApiError;
#[get("/users")]
pub fn list(db: &State<Db>) -> Json<Vec<UserResponse>> {
Json(db.find_all().into_iter().map(UserResponse::from).collect())
}
#[get("/users/<id>")]
pub fn get(id: uuid::Uuid, db: &State<Db>) -> Result<Json<UserResponse>, ApiError> {
db.find(id)
.map(UserResponse::from)
.map(Json)
.ok_or_else(|| ApiError::NotFound(format!("User {} not found", id)))
}
#[post("/users", format = "json", data = "<user>")]
pub fn create(user: Json<CreateUser>, db: &State<Db>) -> (Status, Json<UserResponse>) {
let created = db.create(user.into_inner());
(Status::Created, Json(UserResponse::from(created)))
}
#[put("/users/<id>", format = "json", data = "<user>")]
pub fn update(
id: uuid::Uuid,
user: Json<UpdateUser>,
db: &State<Db>,
) -> Result<Json<UserResponse>, ApiError> {
db.update(id, user.into_inner())
.map(UserResponse::from)
.map(Json)
.ok_or_else(|| ApiError::NotFound(format!("User {} not found", id)))
}
#[delete("/users/<id>")]
pub fn delete(id: uuid::Uuid, db: &State<Db>) -> Result<Status, ApiError> {
if db.delete(id) {
Ok(Status::NoContent)
} else {
Err(ApiError::NotFound(format!("User {} not found", id)))
}
}
主程序 #
rust
#[macro_use] extern crate rocket;
mod models;
mod routes;
mod db;
mod error;
use db::Db;
#[get("/")]
fn index() -> &'static str {
"API v1.0"
}
#[launch]
fn rocket() -> _ {
rocket::build()
.manage(Db::new())
.mount("/", routes![index])
.mount("/api/v1", routes![
routes::user::list,
routes::user::get,
routes::user::create,
routes::user::update,
routes::user::delete
])
}
API测试 #
bash
# 创建用户
curl -X POST http://localhost:8000/api/v1/users \
-H "Content-Type: application/json" \
-d '{"username":"alice","email":"alice@example.com","password":"secret"}'
# 获取用户列表
curl http://localhost:8000/api/v1/users
# 获取单个用户
curl http://localhost:8000/api/v1/users/{id}
# 更新用户
curl -X PUT http://localhost:8000/api/v1/users/{id} \
-H "Content-Type: application/json" \
-d '{"username":"alice_updated"}'
# 删除用户
curl -X DELETE http://localhost:8000/api/v1/users/{id}
下一步 #
掌握了RESTful API后,让我们继续学习 用户认证系统,实现完整的用户认证功能。
最后更新:2026-03-28