如何使用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
相关产品推荐
相关产品推荐

