example

Useage

````rust use askama::Template; use athene::prelude::*; use athene::{html, json, status}; use serde::{Deserialize, Serialize}; use tracing::info;

use validator::{Validate, ValidationError};

[derive(Serialize, Deserialize, Clone, Validate)]

pub struct User { #[validate(email)] pub username: String, #[validate(range(min = 18, max = 20))] pub age: u16, #[validate(custom = "validateuserrole")] pub role: Option, }

fn validateuserrole(role: &str) -> Result<(),ValidationError> { if role.ne("student"){ return Err(ValidationError::new("invalid role")); } Ok(()) }

// ================================ Controller =================================== pub struct UserController {}

// http://127.0.0.1:7878/api/v1/user

[controller(prefix = "api", version = 1, name = "user")]

impl UserController { #[delete("//")] pub async fn deletebyparam(&self, username: String, age: Option) -> (u16, String) { ( 200, format!("username is : {}, and age is : {:?}", username, age), ) }

#[get("/get_query_1")]
pub async fn get_query_1(&self, username: String, age: u16) -> (u16, Json<User>) {
    (200, Json(User { username, age, role: None}))
}

#[get("/get_query_2")]
pub async fn get_query_2(&self, request: Request) -> Result<(u16, Json<User>)> {
    let user = request.query::<User>()?;
    Ok((200, Json(user)))
}

// Context-Type : application/json
#[post("/post_json")]
#[validator]  // The user parameter will be validated
pub async fn post_json(&self, user: Json<User>) -> Result<(u16,Json<User>)> {
    Ok((200, user))
}

// Context-Type : application/x-www-form-urlencoded
#[get("/user_form")]
#[post("/user_form")]
#[validator(exclude("user"))] // The user parameter will not be validated
async fn user_form(&self, user: Form<User>) -> impl Responder {
    (200, user)
}

// Context-Type : application/json  Or application/x-www-form-urlencoded
// Context-Type : application/msgpack Or application/cbor
#[post("/parse_body")]
#[validator] // User will be validated
async fn parse_body(&self, mut req: Request) -> Result<(u16, String)> {
    let user = req.parse::<User>().await?;
    Ok((
        200,
        format!("username = {} and age = {}", user.username, user.age),
    ))
}

// Context-Type : application/multipart-formdata
#[post("/files")]
async fn files(&self, mut req: Request) -> Result<(u16, String)> {
    let files = req.files("files").await?;
    let fist_file_name = files[0].name().unwrap();
    let second_file_name = files[1].name().unwrap();
    let third_file_name = files[2].name().unwrap();
    Ok((
        200,
        format!(
            "fist {}, second {}, third {}",
            fist_file_name, second_file_name, third_file_name
        ),
    ))
}

// Context-Type : application/multipart-formdata
#[post("/upload")]
async fn upload(&self, mut req: Request) -> impl Responder {
    if let Ok(res) = req.upload("file", "temp").await {
        (200, res)
    } else {
        (200, String::from("Bad Request"))
    }
}

}

// ================================ Middleware ====================== struct ApiKeyMiddleware(String);

[middleware]

impl ApiKeyMiddleware { pub fn new(apikey: &str) -> Self { ApiKeyMiddleware(apikey.to_string()) }

async fn next(&self, ctx: Context, chain: &dyn Next) -> Result<Context, Error> {
    if let Some(Ok("Bearer secure-key")) = ctx
        .state
        .request_unchecked()
        .headers()
        .get("authorization")
        .map(|auth_value| auth_value.to_str())
    {
        info!("Authenticated");
    } else {
        info!("Not Authenticated");
    }

    info!(
        "Handler {} will be used",
        ctx.metadata.name.unwrap_or("unknown")
    );
    chain.next(ctx).await
}

}

async fn logmiddleware(ctx: Context, next: &'static dyn Next) -> Result { info!( "new request on path: {}", ctx.state.requestunchecked().uri().path() );

let ctx = next.next(ctx).await?;

info!(
    "new response with status: {}",
    ctx.state.response_unchecked().status()
);
Ok(ctx)

}

// ================================ Handler ===================================

pub async fn hello(_req: Request) -> (u16, &'static str) { (200, "Hello, World!") }

pub async fn user_params(mut req: Request) -> impl Responder { let username = req.param("username"); let age = req.param("age"); let age = age.parse::().unwrap(); (200, Json(User { username, age, role: None })) }

pub async fn login(mut req: Request) -> impl Responder { if let Ok(user) = req.body_mut().parse::>().await { ( 200, format!("username: {} , age: {} ", user.username, user.age), ) } else { (400, String::from("Bad user format")) } }

pub async fn signup(mut req: Request) -> Result<(u16, Json)> { let user = req.bodymut().parse::>().await?; Ok((200, Json(user))) }

pub async fn readbody(mut req: Request) -> Result<(u16, String)> { let body = req.bodymut().parse::().await?; Ok((200, body)) }

// ================================ Router =================================== pub fn userrouter(r: Router) -> Router { r.get("/hello", hello) .get("/{username}/{age}", userparams) .post("/login", login) .post("/signup", signup) .put("/readbody", readbody) }

[tokio::main]

pub async fn main() -> Result<(), Error> { tracing_subscriber::fmt().compact().init();

let app = athene::new()
    .router(|r| {
        // ====================== Closure ==========================
        r.get("/", |_req: Request| async {
            "Welcome to the athene web framework "
        })
        // Content-Disposition: application/octet-stream
        .get("/download", |_req: Request| async {
            let mut res = status!(hyper::StatusCode::OK);
            res.write_file("templates/author.txt", DispositionType::Attachment)?;
            Ok::<_, Error>(res)
        })
        .delete("/delete", |req: Request| async move {
            let path = req.uri().path().to_string();
            (200, path)
        })
        // use json!()
        .patch("/patch", |_req: Request| async {
            let user = User {
                username: "Rustacean".to_string(),
                age: 18,
                role: None
            };
            json!(&user)
        })
        // Template rendering
        .get("/html", |_req: Request| async {
            #[derive(Serialize, Template)]
            #[template(path = "favorite.html")]
            pub struct Favorite<'a> {
                title: &'a str,
                time: i32,
            }

            let love = Favorite {
                title: "rust_lang",
                time: 1314,
            };
            html!(love.render().unwrap())
        })
    })
    .router(user_router)
    .router(|r| r.controller(UserController {}))
    .middleware(|m| {
        m.apply(ApiKeyMiddleware::new("secure-key"), vec!["/"], vec!["/api"])
            .apply(log_middleware, vec!["/api"], None)
    })
    .build();

app.listen("127.0.0.1:7878").await

} ````