JSON处理 #

JSON是现代Web API中最常用的数据交换格式。Rocket通过serde库提供了强大的JSON处理能力。

基本配置 #

添加依赖 #

toml
[dependencies]
rocket = { version = "0.5", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }

JSON请求 #

定义数据结构 #

rust
use rocket::serde::{Deserialize, Serialize};
use rocket::serde::json::Json;

#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
    email: String,
}

接收JSON请求 #

rust
#[post("/users", format = "json", data = "<user>")]
fn create_user(user: Json<User>) -> Json<User> {
    println!("Creating user: {:?}", user);
    user
}

可选JSON字段 #

rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct UpdateUser {
    name: Option<String>,
    email: Option<String>,
}

#[patch("/users/<id>", format = "json", data = "<data>")]
fn update_user(id: u32, data: Json<UpdateUser>) -> String {
    format!("Updating user {}: {:?}", id, data)
}

JSON响应 #

返回JSON #

rust
#[get("/users/<id>")]
fn get_user(id: u32) -> Json<User> {
    Json(User {
        id,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
    })
}

返回JSON数组 #

rust
#[get("/users")]
fn list_users() -> Json<Vec<User>> {
    Json(vec![
        User { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() },
        User { id: 2, name: "Bob".to_string(), email: "bob@example.com".to_string() },
    ])
}

条件JSON响应 #

rust
use rocket::http::Status;

#[get("/users/<id>")]
fn get_user(id: u32) -> Result<Json<User>, Status> {
    if id == 0 {
        Err(Status::NotFound)
    } else {
        Ok(Json(User {
            id,
            name: "Alice".to_string(),
            email: "alice@example.com".to_string(),
        }))
    }
}

高级序列化 #

自定义序列化 #

rust
use rocket::serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    #[serde(rename = "userId")]
    id: u32,
    
    #[serde(rename = "fullName")]
    name: String,
    
    #[serde(skip_serializing_if = "Option::is_none")]
    email: Option<String>,
    
    #[serde(default)]
    role: String,
}

枚举序列化 #

rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
enum Status {
    #[serde(rename = "active")]
    Active,
    
    #[serde(rename = "inactive")]
    Inactive,
    
    #[serde(rename = "pending")]
    Pending,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct UserStatus {
    user_id: u32,
    status: Status,
}

嵌套结构 #

rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct Address {
    street: String,
    city: String,
    country: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct UserWithAddress {
    id: u32,
    name: String,
    address: Address,
}

错误处理 #

自定义错误响应 #

rust
use rocket::serde::{Deserialize, Serialize};
use rocket::serde::json::Json;
use rocket::http::Status;

#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct ErrorResponse {
    error: String,
    code: u16,
}

#[derive(Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
struct CreateUser {
    name: String,
    email: String,
}

#[post("/users", format = "json", data = "<data>")]
fn create_user(data: Json<CreateUser>) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    if data.name.is_empty() {
        return Err((
            Status::BadRequest,
            Json(ErrorResponse {
                error: "Name cannot be empty".to_string(),
                code: 400,
            }),
        ));
    }
    
    Ok(Json(User {
        id: 1,
        name: data.name.clone(),
        email: data.email.clone(),
    }))
}

验证错误 #

rust
use rocket::serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Debug, Deserialize, Validate)]
#[serde(crate = "rocket::serde")]
struct ValidatedUser {
    #[validate(length(min = 3, max = 20))]
    name: String,
    
    #[validate(email)]
    email: String,
}

#[post("/users/validate", format = "json", data = "<data>")]
fn validate_user(data: Json<ValidatedUser>) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    data.validate()
        .map_err(|e| {
            (
                Status::BadRequest,
                Json(ErrorResponse {
                    error: e.to_string(),
                    code: 400,
                }),
            )
        })?;
    
    Ok(Json(User {
        id: 1,
        name: data.name.clone(),
        email: data.email.clone(),
    }))
}

JSON值处理 #

动态JSON #

rust
use rocket::serde::json::{Json, Value};

#[post("/echo", format = "json", data = "<data>")]
fn echo_json(data: Json<Value>) -> Json<Value> {
    data
}

#[post("/transform", format = "json", data = "<data>")]
fn transform_json(data: Json<Value>) -> Json<Value> {
    let mut value = data.into_inner();
    if let Some(obj) = value.as_object_mut() {
        obj.insert("processed".to_string(), Value::Bool(true));
    }
    Json(value)
}

分页响应 #

rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct PaginatedResponse<T> {
    data: Vec<T>,
    page: u32,
    per_page: u32,
    total: u32,
    total_pages: u32,
}

#[get("/users?<page>&<per_page>")]
fn paginated_users(page: Option<u32>, per_page: Option<u32>) -> Json<PaginatedResponse<User>> {
    let page = page.unwrap_or(1);
    let per_page = per_page.unwrap_or(10);
    
    Json(PaginatedResponse {
        data: vec![
            User { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() },
        ],
        page,
        per_page,
        total: 100,
        total_pages: 10,
    })
}

完整示例 #

rust
#[macro_use] extern crate rocket;

use rocket::serde::{Deserialize, Serialize};
use rocket::serde::json::Json;
use rocket::http::Status;
use std::collections::HashMap;
use std::sync::Mutex;
use rocket::State;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[derive(Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
struct CreateUser {
    name: String,
    email: String,
}

#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
struct ErrorResponse {
    error: String,
    code: u16,
}

type Db = Mutex<HashMap<u32, User>>;

#[get("/users")]
fn list_users(db: &State<Db>) -> Json<Vec<User>> {
    let users = db.lock().unwrap();
    Json(users.values().cloned().collect())
}

#[get("/users/<id>")]
fn get_user(id: u32, db: &State<Db>) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    let users = db.lock().unwrap();
    users.get(&id)
        .cloned()
        .map(Json)
        .ok_or_else(|| {
            (
                Status::NotFound,
                Json(ErrorResponse {
                    error: format!("User {} not found", id),
                    code: 404,
                }),
            )
        })
}

#[post("/users", format = "json", data = "<data>")]
fn create_user(
    data: Json<CreateUser>,
    db: &State<Db>,
) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    if data.name.is_empty() {
        return Err((
            Status::BadRequest,
            Json(ErrorResponse {
                error: "Name cannot be empty".to_string(),
                code: 400,
            }),
        ));
    }
    
    let mut users = db.lock().unwrap();
    let id = (users.len() + 1) as u32;
    let user = User {
        id,
        name: data.name.clone(),
        email: data.email.clone(),
    };
    users.insert(id, user.clone());
    Ok(Json(user))
}

#[put("/users/<id>", format = "json", data = "<data>")]
fn update_user(
    id: u32,
    data: Json<CreateUser>,
    db: &State<Db>,
) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    let mut users = db.lock().unwrap();
    
    if let Some(user) = users.get_mut(&id) {
        user.name = data.name.clone();
        user.email = data.email.clone();
        Ok(Json(user.clone()))
    } else {
        Err((
            Status::NotFound,
            Json(ErrorResponse {
                error: format!("User {} not found", id),
                code: 404,
            }),
        ))
    }
}

#[delete("/users/<id>")]
fn delete_user(id: u32, db: &State<Db>) -> Result<Status, (Status, Json<ErrorResponse>)> {
    let mut users = db.lock().unwrap();
    
    if users.remove(&id).is_some() {
        Ok(Status::NoContent)
    } else {
        Err((
            Status::NotFound,
            Json(ErrorResponse {
                error: format!("User {} not found", id),
                code: 404,
            }),
        ))
    }
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .manage(Mutex::new(HashMap::<u32, User>::new()))
        .mount("/api", routes![
            list_users,
            get_user,
            create_user,
            update_user,
            delete_user
        ])
}

测试示例 #

bash
# 创建用户
curl -X POST http://127.0.0.1:8000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","email":"alice@example.com"}'

# 获取用户列表
curl http://127.0.0.1:8000/api/users

# 获取单个用户
curl http://127.0.0.1:8000/api/users/1

# 更新用户
curl -X PUT http://127.0.0.1:8000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice Updated","email":"alice.updated@example.com"}'

# 删除用户
curl -X DELETE http://127.0.0.1:8000/api/users/1

下一步 #

掌握了JSON处理后,让我们继续学习 文件上传,了解如何处理文件上传请求。

最后更新:2026-03-28