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

如何使用rocket_okapi在Swagger UI中展示请求头参数

问题描述

我定义了包含email、password字段的LoginUser结构体,以及对应的请求守卫(request guard),用于检查请求中是否存在这两个请求头。若存在则构建结构体传递给路由,否则返回401 Bad Request。

我的目标是:让Swagger UI不再显示该请求“无参数”,而是明确标识需要这两个请求头参数。当前使用的依赖为rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger", "rapidoc"]},Swagger UI由路由前的#[openapi(tag = "Acess")]宏生成,相关代码如下:

pub struct LoginUser {
    email: String,
    password: String,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for LoginUser {
    type Error = String;

    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        let (email, password) = match (
            request.headers().get_one("email"),
            request.headers().get_one("password"),
        ) {
            (Some(email), Some(password)) => (email, password),
            _ => {
                return Outcome::Failure((
                    Status::BadRequest,
                    "Missing email and/or password headers".into(),
                ))
            }
        };

        let user = LoginUser {
            email: email.to_string(),
            password: match hash(password.to_string(), 10) {
                Ok(hashed_password) => hashed_password,
                Err(_) => return Outcome::Failure((Status::InternalServerError, "".into())),
            },
        };
        Outcome::Success(user)
    }
}

#[openapi(tag = "Acess")]
#[post("/login")]
pub async fn login(
    conn: crate::database::DbConn,
    user: LoginUser,
) {
    // <Verify the user is in the Database>
}
解决方案

要让Swagger UI识别请求守卫所需的请求头,需要为LoginUser实现rocket_okapi提供的OpenApiFromRequest trait,手动声明请求头参数定义。

步骤1:导入必要的依赖项

在代码顶部添加以下导入:

use rocket::request::{FromRequest, Outcome, Request, Status};
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use okapi::openapi3::{Parameter, Schema, SchemaObject, Type};
use okapi::openapi3::ParameterLocation::Header;
use rocket_okapi::gen::OpenApiGenerator;

步骤2:为LoginUser实现OpenApiFromRequest trait

添加以下实现代码,用于定义请求头参数的Swagger元数据:

#[rocket::async_trait]
impl<'r> OpenApiFromRequest<'r> for LoginUser {
    fn openapi_request(gen: &mut OpenApiGenerator) -> rocket_okapi::Result<RequestHeaderInput> {
        // 定义email请求头参数
        let email_param = Parameter {
            name: "email".to_string(),
            location: Header,
            description: Some("用户登录邮箱".to_string()),
            required: true,
            schema: Some(Schema::Object(SchemaObject {
                instance_type: Some(Type::String.into()),
                ..Default::default()
            })),
            ..Default::default()
        };

        // 定义password请求头参数
        let password_param = Parameter {
            name: "password".to_string(),
            location: Header,
            description: Some("用户登录密码".to_string()),
            required: true,
            schema: Some(Schema::Object(SchemaObject {
                instance_type: Some(Type::String.into()),
                ..Default::default()
            })),
            ..Default::default()
        };

        Ok(RequestHeaderInput::Parameters(vec![email_param, password_param]))
    }
}

说明

  • 实现OpenApiFromRequest的openapi_request方法,返回两个请求头参数的完整定义,包括名称、位置、描述、必填性和数据类型。
  • 实现该trait后,#[openapi]宏会自动读取这些参数定义,在Swagger UI中正确展示出需要的email和password请求头参数,替代原来的“无参数”提示。

修改后的完整代码示例

use rocket::request::{FromRequest, Outcome, Request, Status};
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use okapi::openapi3::{Parameter, Schema, SchemaObject, Type};
use okapi::openapi3::ParameterLocation::Header;
use rocket_okapi::gen::OpenApiGenerator;

pub struct LoginUser {
    email: String,
    password: String,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for LoginUser {
    type Error = String;

    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        let (email, password) = match (
            request.headers().get_one("email"),
            request.headers().get_one("password"),
        ) {
            (Some(email), Some(password)) => (email, password),
            _ => {
                return Outcome::Failure((
                    Status::BadRequest,
                    "Missing email and/or password headers".into(),
                ))
            }
        };

        let user = LoginUser {
            email: email.to_string(),
            password: match hash(password.to_string(), 10) {
                Ok(hashed_password) => hashed_password,
                Err(_) => return Outcome::Failure((Status::InternalServerError, "哈希密码失败".into())),
            },
        };
        Outcome::Success(user)
    }
}

#[rocket::async_trait]
impl<'r> OpenApiFromRequest<'r> for LoginUser {
    fn openapi_request(gen: &mut OpenApiGenerator) -> rocket_okapi::Result<RequestHeaderInput> {
        let email_param = Parameter {
            name: "email".to_string(),
            location: Header,
            description: Some("用户登录邮箱".to_string()),
            required: true,
            schema: Some(Schema::Object(SchemaObject {
                instance_type: Some(Type::String.into()),
                ..Default::default()
            })),
            ..Default::default()
        };

        let password_param = Parameter {
            name: "password".to_string(),
            location: Header,
            description: Some("用户登录密码".to_string()),
            required: true,
            schema: Some(Schema::Object(SchemaObject {
                instance_type: Some(Type::String.into()),
                ..Default::default()
            })),
            ..Default::default()
        };

        Ok(RequestHeaderInput::Parameters(vec![email_param, password_param]))
    }
}

#[openapi(tag = "Acess")]
#[post("/login")]
pub async fn login(
    conn: crate::database::DbConn,
    user: LoginUser,
) {
    // 验证用户是否在数据库中的逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:02:52