参数绑定与序列化

参数来源

| 来源 | Request 字段要求 | 状态 | |------|----------------|------| | 路径参数 | 字段名与 `{param}` 一致 | ✅ 已实现 | | JSON Body | `#[derive(Deserialize)]` | ✅ 已实现 | | Query String | 字段名与 query key 一致 | ✅ 已实现(GET/DELETE,需 `Deserialize`) | | 通配符 | `{*name}` 捕获剩余路径 | ✅ 已实现 | | multipart 表单 | 字段类型为 `FormFile` | ✅ 已实现,见[文件上传与下载](file-upload-download.md) |

绑定方式由请求的 `Content-Type` 决定:声明 `multipart/form-data` 时按表单绑定,其余情况按 JSON Body 或路径/Query 绑定。

路径参数

struct GetUserRequest {
    pub id: String,
}

#[get("/api/users/{id}")]
impl IRequest<UserDto> for GetUserRequest {}

路由匹配 `/api/users/abc-123` 后,`id = "abc-123"`。

JSON Body

#[derive(Deserialize)]
pub struct CreateUserRequest {
    pub name: String,
    pub email: String,
}

#[post("/api/users")]
impl IRequest<UserDto> for CreateUserRequest {}

框架从 `HttpContext` 读取 body bytes 并反序列化为 Request struct。

反序列化失败

自动返回 `Error::Serialization`,映射 HTTP 400。

Query String

URL 查询参数(如 `?page=1&size=10`)在 **GET/DELETE** 请求中自动绑定到 Request 字段(字段名与 query key 一致)。Request 类型需 `#[derive(Deserialize)]`;路径参数优先于同名 query 参数。

#[derive(Default, Deserialize)]
pub struct SearchRequest {
    pub q: String,
    pub page: String,
}

#[get("/api/search")]
impl IRequest<SearchResult> for SearchRequest {}

`?q=hello&page=2` → `q = "hello"`, `page = "2"`。

响应序列化

Handler 返回的类型必须实现 `Serialize`:

#[derive(Serialize)]
pub struct UserDto {
    pub id: String,
    pub name: String,
}

框架自动设置 `Content-Type: application/json` 并写入响应体。

返回原始 JSON 值

use webx::Json;

async fn handle(&self, req: MyRequest) -> Result<Json<serde_json::Value>> {
    Ok(Json(serde_json::json!({ "custom": true })))
}

参数绑定宏与 OpenAPI

以下宏标注参数来源;query/path 绑定在 dispatch 层按字段名自动完成:

#[derive(Default, Deserialize, WebxRequestMeta)]
pub struct SearchRequest {
    #[from_query]
    pub q: String,
    #[from_route]
    pub category: String,
}

`#[derive(WebxRequestMeta)]` 将字段元数据注册到 OpenAPI 生成器。也可用 `#[webx_request(query_all)]` 将未标注字段视为 query 参数(排除 `claims` 与 `#[serde(skip)]`)。

`#[from_query]` / `#[from_route]` 不标注时,GET 请求的 query 绑定仍按字段名自动完成,但 OpenAPI 需 `WebxRequestMeta` 才会列出 query 参数。

分页

框架提供内置分页类型:

use webx::{PagedRequest, PagedResponse};

#[derive(Deserialize)]
pub struct ListUsersRequest {
    #[serde(flatten)]
    pub paging: PagedRequest,
}

#[get("/api/users")]
impl IRequest<PagedResponse<UserDto>> for ListUsersRequest {}

小结

路径参数靠字段名匹配,Body 靠 Deserialize,Query 靠 Deserialize + 字段名匹配,响应靠 Serialize。

下一节:[错误处理与 ProblemDetails](error-handling.md)