This version is built on hyper v0.14 and crate async_trait used
1、 Usage MacroController
use athene's validate and file feature
use athene::prelude::*;
use serde::{Deserialize, Serialize};
use validator::Validate;
static INDEX_HTML: &str = r#"<!DOCTYPE html>
<html>
<head>
<title>Upload Test</title>
</head>
<body>
<h1>Upload Test</h1>
<form action="/api/v1/user/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="upload" />
</form>
</body>
</html>
"#;
#[derive(Serialize, Deserialize, Validate, Default, Debug)]
pub struct UserController {
#[validate(email)]
pub username: String,
#[validate(range(min = 18, max = 20))]
pub age: u16,
}
#[controller(prefix = "api", version = 1, name = "user")]
impl UserController {
#[get("/*/**")]
pub async fn match_any_route(&self, req: Request) -> impl Responder {
let uri_path = req.uri().path().to_string();
let method = req.method().to_string();
(201, format!("uri : {}, method: {}", uri_path, method))
}
#[delete("/{username}/{age}")] pub async fn delete_by_param(&self, username: String, age: Option<u16>) -> impl Responder {
(
202,
format!("username is : {}, and age is : {:?}", username, age),
)
}
#[get("/get_query_1")] pub async fn get_query_1(&self, username: String, age: u16) -> impl Responder {
(203, Json(Self { username, age }))
}
#[get("/get_query_2")] pub async fn get_query_2(&self, user: Query<Self>) -> impl Responder {
(203, Json(user.0))
}
#[post("/parse_json_body")]
#[get("/parse_json_body")] async fn parse_json_body(&self, user: Json<Self>) -> impl Responder {
Ok::<_, Error>((206, user))
}
#[post("/parse_form_body")]
#[get("/parse_form_body")] async fn parse_form_body(&self, user: Form<Self>) -> impl Responder {
Ok::<_, Error>((206, user))
}
#[post("/parse_body_vec")]
#[get("/parse_body_vec")]
async fn parse_body_vec(&self,mut req: Request) -> impl Responder {
let vector = req.parse_body::<Vec<u8>>().await?;
Ok::<_, Error>((StatusCode::OK, vector))
}
#[post("/parse_body_string")]
#[get("/parse_body_string")]
async fn parse_body_string(&self,mut req: Request) -> impl Responder {
let vector = req.parse_body::<String>().await?;
Ok::<_, Error>((StatusCode::OK, vector))
}
#[post("/file")]
pub async fn file(&self, mut req: Request) -> impl Responder {
let file = req.file("file").await?;
let file_name = file
.name()
.ok_or_else(|| Error::Other("file not found".to_string()))?;
Ok::<_, Error>((200, file_name.to_string()))
}
#[post("/files")]
pub async fn files(&self, mut req: Request) -> impl Responder {
let files = req.files("files").await?;
let fist_file_name = files[0]
.name()
.ok_or_else(|| Error::Other("file not found".to_string()))?;
let second_file_name = files[1]
.name()
.ok_or_else(|| Error::Other("file not found".to_string()))?;
Ok::<_, Error>((
200,
format!(
"fist_file_name: {}, second_file_name: {}",
fist_file_name, second_file_name
),
))
}
#[post("/upload")]
pub async fn upload(&self, 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"))
}
}
#[post("/uploads")]
pub async fn uploads(&self, mut req: Request) -> impl Responder {
let msg = req.uploads("files", "temp").await?;
Ok::<_, Error>((200, msg))
}
#[get("/download")]
pub async fn download(&self, _req: Request) -> impl Responder {
let mut res = Response::new();
res.write_file("temp/ws.rs", DispositionType::Attachment)?;
Ok::<_, Error>((200, "Download successful"))
}
}
#[tokio::main]
pub async fn main() -> Result<()> {
let app = athene::new().router(|r| {
r.get("/api/v1/user/upload", |_: Request| async {
Html(INDEX_HTML)
})
.controller(UserController::default())
});
let app = app.build();
app.listen("127.0.0.1:7878").await
}
2、Usage BasicController
use athene::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize)]
pub struct AtheneController {
pub label: String,
pub keyword: String,
}
impl Controller for AtheneController {
const BASE_PATH: &'static str = "/api/v1/athene";
fn method(&self) -> Vec<ControllerMethod<Self>>
where
Self: Sized,
{
ControllerBuilder::new()
.post("/add", Self::add)
.delete("/{label}/{keyword}", Self::delete)
.put("/update", Self::update)
.get("/get", Self::get)
.build()
}
}
impl AtheneController {
pub async fn add(&self, mut req: Request) -> impl Responder {
let obj = req.parse::<Self>().await?;
Ok::<_, Error>((200, Json(obj)))
}
pub async fn delete(&self, mut req: Request) -> impl Responder {
let lable = req.param::<String>("label")?;
let keyword = req.param::<String>("keyword")?;
Ok::<_, Error>((300, format!("lable = {},keyword = {}", lable, keyword)))
}
async fn update(&self, mut req: Request) -> impl Responder {
let obj = req.parse::<Self>().await?;
Ok::<_, Error>((200, Json(obj)))
}
async fn get(&self, req: Request) -> impl Responder {
#[derive(Deserialize, Serialize)]
struct QueryParam<'a> {
label: &'a str,
keyword: &'a str,
}
let arg = req.query::<QueryParam>()?;
let res = Response::new();
Ok::<_, Error>(res.json(&arg))
}
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let app = athene::new()
.router(|r| r.controller(AtheneController::default()))
.build();
app.listen("127.0.0.1:7878").await
}
3、Usage Middleware and RouterGroup
use athene::prelude::*;
use headers::{authorization::Bearer, Authorization};
use serde::{Deserialize, Serialize};
use tracing::info;
#[derive(Serialize, Deserialize)]
pub struct User {
pub username: String,
pub age: u16,
}
pub async fn user_params(mut req: Request) -> impl Responder {
let username = req.param("username")?;
let age = req.param::<u16>("age")?;
Ok::<_, Error>((300, Json(User { username, age })))
}
pub async fn login(mut req: Request) -> impl Responder {
if let Ok(user) = req.parse::<User>().await {
(
201,
format!("username: {} , age: {} ", user.username, user.age),
)
} else {
(400, String::from("Bad user format"))
}
}
pub async fn sign_up(mut req: Request) -> impl Responder {
let user = req.parse::<User>().await?;
Ok::<_, Error>((211, Json(user)))
}
pub async fn body_to_vec_u8(mut req: Request) -> impl Responder {
let body = req.parse_body::<Vec<u8>>().await?;
Ok::<_, Error>((500, body))
}
pub async fn body_to_string(mut req: Request) -> impl Responder {
let body = req.parse_body::<String>().await?;
Ok::<_, Error>((404, body))
}
pub fn user_router(r: Router) -> Router {
r.group("///user/**/")
.get("/{username}/{age}", user_params)
.post("/login", login)
.post("/sign_up", sign_up)
.put("/body_to_vec_u8", body_to_vec_u8)
.post("/body_to_string", body_to_string)
}
pub async fn log_middleware(ctx: Context, next: &'static dyn Next) -> Result {
info!(
"new request on path: {}",
ctx.state.request_unchecked().uri().path()
);
let ctx = next.next(ctx).await?;
info!(
"new response with status: {}",
ctx.state.response_unchecked().status()
);
Ok(ctx)
}
struct ApiKeyMiddleware {
api_key: String,
}
#[middleware]
impl ApiKeyMiddleware {
async fn next(&self, ctx: Context, chain: &dyn Next) -> Result {
if let Some(bearer) = ctx
.state
.request_unchecked()
.header::<Authorization<Bearer>>()
{
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");
Ok(ctx)
}
} else {
info!("Not Authenticated, ");
Ok(ctx)
}
}
}
#[tokio::main]
pub async fn main() -> Result<()> {
tracing_subscriber::fmt().compact().init();
let app = athene::new()
.router(user_router)
.middleware(|m| {
m.apply(log_middleware, vec!["/"], None).apply(
ApiKeyMiddleware {
api_key: "athene".to_string(),
},
vec!["/user/login", "/user/sign_up"],
vec!["/user/body_to_vec_u8","/user/body_to_string"],
)
})
.build();
app.listen("127.0.0.1:7878").await
}