athene 1.0.6

A simple and lightweight rust web framework based on hyper
Documentation

Useage

use askama::Template;
#[cfg(feature = "file")]
use athene::DispositionType;
use athene::{Error, Middleware, Next, Request, Response, Result, StatusCode};
use route::fifth::fifth_router;
use serde::{Deserialize, Serialize};
use std::pin::Pin;
use tera::{Context, Tera};

#[derive(Serialize, Deserialize)]
pub struct User {
    name: String,
    age: i32,
}

// http://127.0.0.1:8081/api/hello/rust-lang
pub async fn hello(req: Request) -> Result {
    let name: String = req.param("name").unwrap();
    let mut res = Response::new();
    res.text(name)?;
    Ok(res)
}

// http://127.0.0.1:8081/welcome?name=admin2029&age=21
pub async fn welcome(req: Request) -> Result {
    let user = req.query::<User>().unwrap();
    let mut res = Response::new();
    res.json(&user)?;
    Ok(res)
}

// Context-Type : application/json
pub async fn login(req: Request) -> Result {
    let mut req = req;
    let user = req.parse::<User>().await?;
    let mut res = Response::new();
    res.json(&user)?;
    Ok(res)
}

// Context-Type : application/x-www-form-urlencoded
pub async fn form_encode(req: Request) -> Result{
    #[derive(Deserialize,Serialize)]
    struct Rust {
        version: String,
        edition: String,
    }

    let mut req = req;
    let rust = req.parse::<Rust>().await?;
    let mut res = Response::new();
    res.json(&rust)?;
    Ok(res)
}

// Context-Type : application/multipart-formdata
#[cfg(feature = "file")]
pub async fn upload(req: Request) -> Result {
    let mut req = req;
    let info = req.upload("file", "temp").await?;
    use athene::IntoResponse;
    info.response()
}

// Context-Type : application/multipart-formdata
#[cfg(feature = "file")]
pub async fn uploads(req: Request) -> Result {
    let mut req = req;
    let info = req.uploads("files", "temp").await?;
    use athene::IntoResponse;
    info.response()
}

// Content-Disposition: application/octet-stream
#[cfg(feature = "file")]
pub async fn download(_req: Request) -> Result {
    let mut res = Response::new();
    res.write_file("templates/author.txt", DispositionType::Attachment)?;
    Ok(res)
}

// Response redirect
pub async fn index(_req: Request) -> Result {
    println!("redirect handler");
    Response::redirect(StatusCode::MOVED_PERMANENTLY, "/api/rust")
}

// Response redirect
pub async fn permanent(_req: Request) -> Result {
    Response::redirect(StatusCode::PERMANENT_REDIRECT, "/api/code")
}

// Response redirect
pub async fn temporary(_req: Request) -> Result {
    Response::redirect(StatusCode::TEMPORARY_REDIRECT, "/api/world")
}

// Content-Location
pub async fn location(_req: Request) -> Result {
    Response::location("/")
}

// askama template
pub async fn askama_template(_: Request) -> Result {
    #[derive(Serialize, Hash, Eq, PartialEq, Clone, Template)]
    #[template(path = "favorite.html")]
    pub struct Favorite<'a> {
        title: &'a str,
        time: i32,
    }

    let love = Favorite {
        title: "rust_lang",
        time: 1314,
    };

    let mut res = Response::new();
    let love = love.render()?;
    res.html(love)?;
    Ok(res)
}

// tera template
pub async fn tera_template(_: 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 mut res = Response::new();
    let love = tera.render("index.html", &ctx)?;
    res.html(love)?;
    Ok(res)
}

// Define a middleware
#[derive(Debug)]
pub struct Logger;

#[async_trait::async_trait]
impl Middleware for Logger {
    async fn handle(self: Pin<&Self>, request: Request, next: Next<'_>) -> Result {
        
        if request.uri().path().starts_with("/auth") && request.method().eq("GET"){
            let res = next.next(request).await?;
            return Ok(res);
        } else {
            use athene::IntoResponse;
            "Logger middleware is used".response()
        }
    }
}

pub(crate) mod route {

    pub(crate) mod first {
        use crate::{index, permanent, temporary, welcome};

        pub(crate) fn first_router() -> athene::Router {
            let mut router = athene::new();
            router.get("/", index);
            router.get("/permanent", permanent);
            router.get("/temporary", temporary);
            router.get("/welcome", welcome);
            router
        }
    }

    pub(crate) mod second {
        use crate::{askama_template, location, route::first::first_router, tera_template};
        #[cfg(feature = "file")]
        use crate::{download, upload, uploads};

        pub(crate) fn second_router() -> athene::Router {
            let mut router = first_router();
            #[cfg(feature = "file")]
            router.post("/upload", upload);
            #[cfg(feature = "file")]
            router.post("/uploads", uploads);
            #[cfg(feature = "file")]
            router.get("/download", download);
            router.get("/location", location);
            router.get("/askama_template", askama_template);
            router.get("/tera_template", tera_template);
            router
        }
    }

    pub(crate) mod third {
        use super::second::second_router;
        use athene::{Request, StatusCode};

        pub(crate) fn third_router() -> athene::Router {
            let mut router = second_router();
            router.group("/closure", |base| {
                base.get("/str", |_req| async { "closure str" });
                base.post("/string", |_| async { String::from("closure string") });
                base.put("/vec/", |_| async { [1, 3, 5, 7, 9].to_vec() });
                base.delete("/status", |_| async { StatusCode::NO_CONTENT });
                base.options("/empty", |_| async {});
                base.head("/empty/bracket", |_| async { () });
                base.put("/remote_addr", |req: Request| async move {
                    let addr = req.remote_addr().unwrap();
                    let addr = addr.to_string();
                    addr
                });
                base.patch("/remote_ip", |req: Request| async move {
                    let ip = req.ip().unwrap();
                    let ip = ip.to_string();
                    ip
                });
                base.post("/status/value", |_| async {
                    (StatusCode::NOT_FOUND, "welcome to my world")
                });
            });
            router
        }
    }

    pub(crate) mod fifth {
        use super::third::third_router;
        use crate::{hello, login,Logger,form_encode};

        pub(crate) fn fifth_router() -> athene::Router {
            let mut router = third_router();
            router.group("/api", |base| {
                base.get("/hello/{name}", hello);
                base.get("/world", |_|async {
                    "world"
                });
                base.get("/code", |_| async {
                    "code handler"
                });
                base.get("/rust", |_| async {
                    "welcome to rust_lang world"
                });
                base.group("/user", |user| {
                    user.post("/", login);
                    user.post("/form_encode",form_encode);
                });
            });

            router.middleware(Logger).group("/auth", |base| {

                base.get("/success",|req: athene::Request| async move {
                    format!("{} {}",req.uri().path(),req.method())
                });

                base.post("/failed",|_| async {
                    "failed"
                });

            });
            router
        }
    }
}

#[tokio::main]
pub async fn main() -> Result<(), Error> {
    let router = fifth_router();
    router.listen("127.0.0.1:8081").await
}

templates/index.html

<title>{{title}}</title>
<ul>
  {% for one in product -%}
  <li><a href="{{ one.url | safe }}">{{ one.name }}</a></li>
  {%- endfor %}
</ul>

templates/favorite.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Rust is one of my favorite programming languages</title>
</head>

<body>
    <h4>{{title}}</h4>
    <p>{{time}}</p>
</body>

</html>