You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rocket 0.5中GET请求查询参数优雅验证方案求助

Rocket 0.5 + rocket_okapi 0.8.0 GET查询参数优雅验证方案

核心思路:基于FromForm的字段级验证+自定义错误适配OpenAPI

针对你遇到的路由跳过、OpenAPI兼容冲突等问题,以下是可落地的解决方案:

1. 结构体字段级验证配置

直接在查询参数结构体上通过#[field(validate = ...)]完成基础校验,同时保留JsonSchema派生以支持OpenAPI文档生成:

use rocket::form::{FromForm, Validate};
use rocket_okapi::JsonSchema;

#[derive(Debug, FromForm, JsonSchema, Validate)]
pub struct HistoryRequest {
    #[field(validate = required)]
    #[field(validate = len(1..=100))]
    user_id: String,

    #[field(validate = required)]
    #[field(validate = range(1..=1000))]
    page: u32,

    #[field(validate = required)]
    #[field(validate = range(10..=50))]
    page_size: u32,
}

通过required约束参数必须存在,配合长度、范围验证,直接在字段层面完成规则校验。

2. 自定义查询参数包装器适配错误与OpenAPI

由于直接使用Result<HistoryRequest, rocket::form::Error>会导致JsonSchema不兼容,我们可以实现一个通用包装器ValidatedQuery<T>,统一处理错误转换并实现JsonSchema:

use rocket::form::{FromForm, FormError};
use rocket_okapi::JsonSchema;
use serde::Serialize;

// 结构化错误返回体
#[derive(Debug, Serialize, JsonSchema)]
pub struct QueryValidationError {
    field: String,
    message: String,
}

// 通用查询参数包装器
#[derive(JsonSchema)]
pub struct ValidatedQuery<T>(pub T);

impl<T: FromForm + JsonSchema> FromForm for ValidatedQuery<T> {
    type Error = Vec<QueryValidationError>;

    fn from_form(items: &mut rocket::form::Items<'_, '_>) -> rocket::form::Result<Self, Self::Error> {
        match T::from_form(items) {
            Ok(data) => Ok(ValidatedQuery(data)),
            Err(form_error) => {
                let errors = form_error.into_iter()
                    .map(|e| QueryValidationError {
                        field: e.name.unwrap_or("unknown".to_string()),
                        message: e.to_string(),
                    })
                    .collect();
                Err(errors)
            }
        }
    }
}

这个包装器会将FromForm的原生错误转换为可序列化的结构化数组,同时因为实现了JsonSchema,rocket_okapi可以正常生成对应的OpenAPI schema。

3. 路由层处理验证结果并返回响应

在路由中使用ValidatedQuery<HistoryRequest>捕获参数,错误时返回400 Bad Request与结构化错误:

use rocket::{get, http::Status, serde::json::Json};
use rocket_okapi::{openapi, openapi_get_routes};

#[openapi]
#[get("/history?<query..>")]
pub async fn get_history(
    query: Result<ValidatedQuery<HistoryRequest>, Vec<QueryValidationError>>,
) -> Result<Json<Vec<HistoryItem>>, (Status, Json<Vec<QueryValidationError>>)> {
    match query {
        Ok(ValidatedQuery(req)) => {
            // 执行业务逻辑并返回数据
            let history = fetch_history(&req.user_id, req.page, req.page_size).await;
            Ok(Json(history))
        }
        Err(errors) => Err((Status::BadRequest, Json(errors))),
    }
}

// 注册带OpenAPI文档的路由
pub fn routes() -> Vec<rocket::Route> {
    openapi_get_routes![get_history]
}

该方案既保留了FromForm的验证能力,又能在参数缺失/无效时返回清晰的JSON错误,同时完全兼容OpenAPI文档生成。

4. 避免重复实现的技巧

ValidatedQuery<T>是通用包装器,所有需要验证的查询参数结构体只要实现FromForm和JsonSchema,就能直接套用,无需为每个结构体单独编写FromRequest逻辑。

内容的提问来源于stack exchange,提问作者FluffyDango

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:48:26