use potato::{HttpRequest, HttpResponse, HttpServer, OnceCache, SessionCache};
#[potato::preprocess]
fn my_preprocess(_req: &mut HttpRequest) -> anyhow::Result<()> {
Ok(())
}
#[potato::controller]
pub struct UsersController<'a> {
pub once_cache: &'a OnceCache,
pub sess_cache: &'a SessionCache,
}
#[potato::controller("/api/users")]
#[potato::preprocess(my_preprocess)]
impl<'a> UsersController<'a> {
#[potato::http_get] pub async fn get(&self) -> anyhow::Result<&'static str> {
Ok("get users data")
}
#[potato::http_post] pub async fn post(&mut self) -> anyhow::Result<&'static str> {
Ok("post users data")
}
#[potato::http_get("/any")] pub async fn get_any(&self) -> anyhow::Result<&'static str> {
Ok("get users any data")
}
}
#[potato::http_get("/api/public")]
async fn public_handler() -> HttpResponse {
HttpResponse::text("Public endpoint")
}
#[potato::http_get("/api/private")]
async fn private_handler(cache: &mut SessionCache) -> HttpResponse {
let count: u32 = cache.get("count").unwrap_or(0);
let body = serde_json::json!({ "count": count });
HttpResponse::json(body.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "openapi")]
#[tokio::test]
async fn test_controller_swagger_auth_marker() {
use std::time::Duration;
let port = 18889;
let server_addr = format!("127.0.0.1:{}", port);
let mut server = HttpServer::new(&server_addr);
server.configure(|ctx| {
ctx.use_openapi("/doc/");
});
let server_handle = tokio::spawn(async move {
let _ = server.serve_http().await;
});
tokio::time::sleep(Duration::from_millis(500)).await;
let url = format!("http://{}/doc/index.json", server_addr);
match potato::get(&url, vec![]).await {
Ok(res) => {
let swagger_json = match &res.body {
potato::HttpResponseBody::Data(data) => {
String::from_utf8_lossy(data).to_string()
}
potato::HttpResponseBody::Stream(_) => "{}".to_string(),
};
let swagger: serde_json::Value =
serde_json::from_str(&swagger_json).expect("Invalid JSON");
println!(
"Swagger JSON:\n{}",
serde_json::to_string_pretty(&swagger).unwrap()
);
let paths = swagger["paths"].as_object().unwrap();
let users_get = &paths["/api/users"]["get"];
assert!(
users_get.get("security").is_some(),
"/api/users GET should have security marker (has &self receiver)"
);
println!("✅ /api/users GET correctly has security requirement");
let users_post = &paths["/api/users"]["post"];
assert!(
users_post.get("security").is_some(),
"/api/users POST should have security marker (has &mut self receiver)"
);
println!("✅ /api/users POST correctly has security requirement");
let users_any_get = &paths["/api/users/any"]["get"];
assert!(
users_any_get.get("security").is_some(),
"/api/users/any GET should have security marker (has &self receiver)"
);
println!("✅ /api/users/any GET correctly has security requirement");
let public_get = &paths["/api/public"]["get"];
assert!(
public_get.get("security").is_none(),
"/api/public GET should NOT have security marker"
);
println!("✅ /api/public GET correctly has NO security requirement");
let private_get = &paths["/api/private"]["get"];
assert!(
private_get.get("security").is_some(),
"/api/private GET should have security marker (has SessionCache parameter)"
);
println!("✅ /api/private GET correctly has security requirement");
let security_schemes = &swagger["components"]["securitySchemes"]["bearerAuth"];
assert!(
security_schemes.get("type").is_some(),
"bearerAuth security scheme should be defined"
);
assert_eq!(
security_schemes["type"].as_str().unwrap(),
"http",
"bearerAuth type should be 'http'"
);
println!("✅ bearerAuth security scheme correctly defined");
server_handle.abort();
}
Err(e) => {
panic!("Failed to get swagger json: {}", e);
}
}
}
}