Useage

````rust use askama::Template; use athene::headers::{authorization::Bearer, Authorization}; use athene::{anyhow, prelude::*}; use athene::{html, json, status, text, with, Message}; use serde::{Deserialize, Serialize}; use tera::{Context, Tera}; use tracing::{debug, error, info, warn};

// askama template pub async fn askamatemplate(: Request) -> Result { #[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()?)

}

// tera template pub async fn teratemplate(: Request) -> Result { #[derive(Serialize)] struct Awesome<'a> { url: &'a str, name: &'a str, }

let tera = Tera::new("templates/*")?;
let mut ctx = Context::new();
ctx.insert("title", "Welcome to rust-lang world!");
ctx.insert(
    "product",
    &vec![
        Awesome {
            url: "https://github.com/rust-lang",
            name: "rust-lang",
        },
        Awesome {
            url: "https://github.com/lapce/lapce",
            name: "lapce",
        },
    ],
);

let love = tera.render("index.html", &ctx)?;
with!(love, "text/html; charset=utf-8")
// html!(love)

}

struct Logger;

[async_trait]

impl Middleware for Logger { async fn apply(&self, req: Request, next: Next<'>) -> Result { let method = req.method().tostring(); let uri = req.uri().tostring(); debug!(%method, %uri, "request"); let result = next.next(req).await?; logresponse(method, uri, &result); Ok(result) } }

fn logresponse(method: String, uri: String, resp: &Response) { let status = resp.asref().status(); if status.isservererror() { error!(%method, %uri, %status, "response"); } else if status.isclienterror() { warn!(%method, %uri, %status, "response"); } else { info!(%method, %uri, %status, "response"); } }

struct AuthCheck;

[async_trait]

impl Middleware for AuthCheck { async fn apply(&self, req: Request, next: Next<'_>) -> Result { let auth = req.header::>(); match auth { None => return Ok(Response::status(StatusCode::UNAUTHORIZED)), Some(bearer) => { info!("bearer token: {}", bearer.0.token()); next.next(req).await } } } }

[tokio::main]

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

let mut app = athene::new();

app.middleware(Logger);

app.get("/hello", |_| async { "Hello world!\n\n" })
    .get("/askama_template", askama_template)
    .get("/tera_template", tera_template)
    .get("/param/:name", |req: Request| async move {
        let name = req.param("name").unwrap();
        name.to_string()
    })
    .get("/query", |req: Request| async move {
        #[derive(Serialize, Deserialize)]
        struct Book {
            title: String,
            is_publish: bool,
        }
        json!(req.query::<Book>()?)
    })
    // Context-Type : application/x-www-form-urlencoded
    .post("/form-urlencoded", |mut req: Request| async move {
        #[derive(Serialize, Deserialize)]
        struct Rust {
            version: String,
            edition: String,
        }
        json!(req.parse::<Rust>().await?)
    })
    // Context-Type : application/json
    .post("/json", |mut req: Request| async move {
        #[derive(Serialize, Deserialize)]
        struct User {
            name: String,
            age: i32,
        }
        let user = req.parse::<User>().await?;
        json!(user)
    })
    // Context-Type : application/multipart-formdata
    .post("/file", |mut req: Request| async move {
        let file = req.file("file").await?;
        text!(file.name().unwrap().to_string())
    })
    // Context-Type : application/multipart-formdata
    .post("/files", |mut req: Request| async move {
        let files = req.files("files").await?;
        let fist_file_name = files[0].name().unwrap();
        let second_file_name = files[1].name().unwrap();
        let name = format!("fist {}, second {}", fist_file_name, second_file_name);
        text!(name)
    })
    // Content-Disposition: application/octet-stream
    .get("/download", |_| async {
        let mut res = Response::default();
        res.write_file("templates/author.txt", DispositionType::Attachment)?;
        Ok(res)
    })
    // websocket  ws://127.0.0.1:8888/ws/admin  http://www.jsons.cn/websocket/
    .ws("/ws/:name", |req, mut tx, mut rx| async move {
        let name = req.param("name").unwrap();

        while let Some(msg) = rx.receive().await? {
            println!("message: {}", msg);
            let reply = Message::text(format!("Hello {},", name));
            tx.send(reply).await?;
        }

        println!("websocket closed");
        Ok(())
    });

let mut api = athene::new();

api.middleware(AuthCheck);

api.get("check", |req: Request| async move {
    let mut res = status!(StatusCode::OK);
    res.text(req.uri().to_string())?;
    Ok(res)
});

api.get("user/:name", |req: Request| async move {
    let mut res = status!(StatusCode::OK);
    let resp = format!("uri = {}\nparams = {:?}\n", req.uri(), req.params());
    res.text(resp)?;
    Ok(res)
});

app.group("/api/:version", api);

// http://127.0.0.1:8888/tera_template
app.static_files("/public/*", "public");

app.listen("127.0.0.1:8888").await?;
Ok(())

} ````

templates/index.html

````html {{title}}

````

templates/favorite.html

````html

Rust is one of my favorite programming languages

{{title}}

{{time}}

````