use athene::prelude::*; use headers::{authorization::Bearer, Authorization}; use tracing::info; use validator::Validate; #[derive(Debug, Serialize, Deserialize, Validate, Default)] pub struct UserController { #[validate(email)] pub email: String, // admin@outlook.com #[validate(range(min = 18, max = 20))] pub age: u16, } // http://127.0.0.1:7878/api/v1/user #[controller(prefix = "api", version = 1, name = "user")] impl UserController { // http://127.0.0.1:7878/api/v1/user/query/?email=admin@outlook.com&age=19 // query params #[get("/query")] // user will be validate pub async fn query(&self, user: Query) -> impl Responder { (200, Json(user.0)) } // http://127.0.0.1:7878/api/v1/user/create // Context-Type : application/json #[post("/create")] // user will be validate async fn create(&self, user: Json) -> impl Responder { Ok::<_, Error>((200, user)) } // http://127.0.0.1:7878/api/v1/user/update // Context-Type : application/x-www-form-urlencoded #[put("/update")] #[validator(exclude("user"))] // user will not be validate async fn update(&self, user: Form) -> impl Responder { Ok::<_, Error>((200, user)) } // http://127.0.0.1:7878/api/v1/user/admin@outlook.com/18 // uri path params #[delete("/{email}/{age}")] pub async fn delete(&self, email: String, age: Option) -> impl Responder { ( StatusCode::OK, format!("email is : {}, and age is : {:?}", email, age), ) } // http://127.0.0.1:7878/api/v1/user/query_get/?email=admin@outlook.com&age=29 // query params #[get("/query_get")] pub async fn query_get(&self, email: String, age: u16, mut req: Request) -> impl Responder { let cookie = req.cookie("MyCookie").unwrap(); println!("cookie = {:?}", cookie); (200, Json(Self { email, age })) } // http://127.0.0.1:7878/api/v1/user/get_cookies #[get("/get_cookies")] pub async fn get_cookies(&self,cookie_jar: CookieJar) -> impl Responder { let cookie = cookie_jar.get("Cookie1").unwrap(); println!("cookie = {:?}", cookie); } // http://127.0.0.1:7878/api/v1/user/set_cookies #[get("/set_cookies")] pub async fn set_cookies(&self) -> impl Responder { let mut cookie = Cookie::new("Cookie1", "athene"); cookie.set_path("/"); let mut cookie2 = Cookie::new("Cookie2", "athene2"); cookie2.set_path("/"); let mut cookie_jar = CookieJar::new(); cookie_jar.add(cookie); cookie_jar.add(cookie2); (200, cookie_jar) } } // Function Middleware pub async fn log_middleware(ctx: Context, next: &dyn Next) -> Result { let uri_path = ctx.state.request().map(|req| req.uri().path()); info!("new request on path: {:?}", uri_path); let ctx = next.next(ctx).await?; let status = ctx.state.response().map(|res| res.status()); info!("new response with status: {:?}", status); Ok(ctx) } struct ApiKeyMiddleware { api_key: String, } #[derive(Debug, Deserialize, Serialize)] pub struct MiddlewareError { pub code: u32, pub msg: String, pub data: T, } // Macro Middleware #[middleware] impl ApiKeyMiddleware { async fn next(&self, ctx: Context, chain: &dyn Next) -> Result { let req = ctx.state.request()?; if let Some(bearer) = req.header::>() { let token = bearer.0.token(); if token == self.api_key { info!( "Handler {} will be used", ctx.metadata.name.unwrap_or("unknown") ); chain.next(ctx).await } else { info!("Invalid token"); let res = MiddlewareError { code: 400, msg: String::from("Invalid token"), data: "Invalid token", }; Err(Error::Response(StatusCode::UNAUTHORIZED, json!(res))) } } else { info!("Not Authenticated"); Err(Error::Response( StatusCode::UNAUTHORIZED, json!("Not Authenticated"), )) } } } // http://127.0.0.1:7878/upload pub async fn upload(mut req: Request) -> impl Responder { let res = req.upload("file", "temp").await?; if res > 0 { Ok::<_, Error>((200, "File uploaded successfully")) } else { Ok::<_, Error>((400, "File upload failed")) } } fn file_router(r: Router) -> Router { r.get("/upload", |_: Request| async { Html(INDEX_HTML) }) .post("/upload", upload) } // Websocket ws://127.0.0.1:7878/hello/ws http://www.jsons.cn/websocket/ pub async fn ws( mut req: Request, mut ws: WebSocket, ) -> Result<()> { let name = req.param::("name")?; while let Ok(msg) = ws.receive().await { if let Some(msg) = msg { match msg { Message::Text(text) => { let text = format!("{},{}", name, text); ws.send(Message::Text(text)).await?; } Message::Close(_) => break, _ => {} } } } Ok(()) } #[tokio::main] pub async fn main() -> Result<()> { tracing_subscriber::fmt().compact().init(); let app = athene::new().router(file_router).router(|r| { r.controller(UserController::default()) .ws("/{name}/ws", ws) .get("/**", StaticDir::new("./").listing(true)) }); let app = app.middleware(|m| { m.apply(log_middleware, vec!["/"], None) .apply( ApiKeyMiddleware { api_key: "athene".to_string(), }, vec!["/api/v1/user"], vec!["/upload"], ) }); app.listen("127.0.0.1:7878").await } static INDEX_HTML: &str = r#" Upload Test

Upload Test

"#;