#web-framework #web #框架 #http

graphul

优化、加速、扩展您的微服务并节省金钱 💵

18个版本 (2个稳定版)

1.0.1 2023年9月25日
0.5.6 2023年3月24日
0.5.5 2023年2月18日
0.4.5 2022年12月5日
0.4.3 2022年11月17日

#159 in HTTP服务器

Download history 182/week @ 2024-03-13 93/week @ 2024-03-20 96/week @ 2024-03-27 59/week @ 2024-04-03 39/week @ 2024-04-10 49/week @ 2024-04-17 32/week @ 2024-04-24 28/week @ 2024-05-01 11/week @ 2024-05-08 17/week @ 2024-05-15 62/week @ 2024-05-22 89/week @ 2024-05-29 53/week @ 2024-06-05 50/week @ 2024-06-12 39/week @ 2024-06-19 33/week @ 2024-06-26

每月181次 下载
kickable 中使用

MIT 许可证

2.5MB
1K SLoC

Graphul

Graphul 是一个受 Express 启发的 Web框架,使用强大的提取系统。Graphul旨在通过友好的语法改进、加速和扩展您的微服务,由 Rust 构建。这意味着Graphul可以免费获得内存安全、可靠性、并发性和性能,有助于在基础设施上节省资金。

用比特币买咖啡 ☕️

Discord 加入我们的Discord服务器,与其他Graphul社区成员交流!

⚡️ 快速入门

use graphul::{Graphul, http::Methods};


#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/", || async {
        "Hello, World 👋!"
    });

    app.run("127.0.0.1:8000").await;
}

👀 示例

以下是一些常见示例。如果您想看到更多代码示例,请访问我们的 示例文件夹

常见示例

🛫 Graphul 与最著名的框架对比

Graphul

📖 上下文

use graphul::{http::Methods, Context, Graphul};

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    // /samuel?country=Colombia
    app.get("/:name", |c: Context| async move {
        /*
           statically typed query param extraction
           let value: Json<MyType> = match c.parse_params().await
           let value: Json<MyType> = match c.parse_query().await
        */

        let name = c.params("name");
        let country = c.query("country");
        let ip = c.ip();

        format!("My name is {name}, I'm from {country}, my IP is {ip}",)
    });

    app.run("127.0.0.1:8000").await;
}

📖 JSON

use graphul::{Graphul, http::Methods, extract::Json};
use serde_json::json;

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/", || async {
        Json(json!({
            "name": "full_name",
            "age": 98,
            "phones": [
                format!("+44 {}", 8)
            ]
        }))
    });

    app.run("127.0.0.1:8000").await;
}

📖 资源

use std::collections::HashMap;

use graphul::{
    async_trait,
    extract::Json,
    http::{resource::Resource, response::Response, StatusCode},
    Context, Graphul, IntoResponse,
};
use serde_json::json;

type ResValue = HashMap<String, String>;

struct Article;

#[async_trait]
impl Resource for Article {
    async fn get(c: Context) -> Response {
        let posts = json!({
            "posts": ["Article 1", "Article 2", "Article ..."]
        });
        (StatusCode::OK, c.json(posts)).into_response()
    }

    async fn post(c: Context) -> Response {
        // you can use ctx.parse_params() or ctx.parse_query()
        let value: Json<ResValue> = match c.payload().await {
            Ok(data) => data,
            Err(err) => return err.into_response(),
        };

        (StatusCode::CREATED, value).into_response()
    }

    // you can use put, delete, head, patch and trace
}

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.resource("/article", Article);

    app.run("127.0.0.1:8000").await;
}

📖 静态文件

use graphul::{Graphul, FolderConfig, FileConfig};

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    // path = "/static", dir = public
    app.static_files("/static", "public", FolderConfig::default());

    // single page application
    app.static_files("/", "app/build", FolderConfig::spa());

    app.static_file("/about", "templates/about.html", FileConfig::default());

    app.run("127.0.0.1:8000").await;
}

🌟 带自定义配置的静态文件

use graphul::{Graphul, FolderConfig, FileConfig};

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.static_files("/", "templates", FolderConfig {
        // single page application
        spa: false,
        // it support gzip, brotli and deflate
        compress: true,
        // Set a specific read buffer chunk size.
        // The default capacity is 64kb.
        chunk_size: None,
        // If the requested path is a directory append `index.html`.
        // This is useful for static sites.
        index: true,
        // fallback - This file will be called if there is no file at the path of the request.
        not_found: Some("templates/404.html"), // or None
    });

    app.static_file("/path", "templates/about.html", FileConfig {
        // it support gzip, brotli and deflate
        compress: true,
        chunk_size: Some(65536) // buffer capacity 64KiB
    });

    app.run("127.0.0.1:8000").await;
}

📖 组

use graphul::{
    extract::{Path, Json},
    Graphul,
    http::{ Methods, StatusCode }, IntoResponse
};

use serde_json::json;

async fn index() -> &'static str {
    "index handler"
}

async fn name(Path(name): Path<String>) -> impl IntoResponse {
    let user = json!({
        "response": format!("my name is {}", name)
    });
    (StatusCode::CREATED, Json(user)).into_response()
}

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    // GROUP /api
    let mut api = app.group("api");

    // GROUP /api/user
    let mut user = api.group("user");

    // GET POST PUT DELETE ... /api/user
    user.resource("/", Article);

    // GET /api/user/samuel
    user.get("/:name", name);

    // GROUP /api/post
    let mut post = api.group("post");

    // GET /api/post
    post.get("/", index);

    // GET /api/post/all
    post.get("/all", || async move {
        Json(json!({"message": "hello world!"}))
    });

    app.run("127.0.0.1:8000").await;
}

📖 共享状态

use graphul::{http::Methods, extract::State, Graphul};

#[derive(Clone)]
struct AppState {
    data: String
}

#[tokio::main]
async fn main() {
    let state = AppState { data: "Hello, World 👋!".to_string() };
    let mut app = Graphul::share_state(state);

    app.get("/", |State(state): State<AppState>| async {
        state.data
    });

    app.run("127.0.0.1:8000").await;
}

📖 与资源共享状态

use graphul::{
    async_trait,
    http::{resource::Resource, response::Response, StatusCode},
    Context, Graphul, IntoResponse,
};
use serde_json::json;

struct Article;

#[derive(Clone)]
struct AppState {
    data: Vec<&'static str>,
}

#[async_trait]
impl Resource<AppState> for Article {

    async fn get(ctx: Context<AppState>) -> Response {
        let article = ctx.state();

        let posts = json!({
            "posts": article.data,
        });
        (StatusCode::OK, ctx.json(posts)).into_response()
    }

    // you can use post, put, delete, head, patch and trace

}

#[tokio::main]
async fn main() {
    let state = AppState {
        data: vec!["Article 1", "Article 2", "Article 3"],
    };
    let mut app = Graphul::share_state(state);

    app.resource("/article", Article);

    app.run("127.0.0.1:8000").await;
}

📖 中间件

use graphul::{
    Req,
    middleware::{self, Next},
    http::{response::Response,Methods},
    Graphul
};

async fn my_middleware( request: Req, next: Next ) -> Response {

    // your logic

    next.run(request).await
}

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/", || async {
        "hello world!"
    });
    app.middleware(middleware::from_fn(my_middleware));

    app.run("127.0.0.1:8000").await;
}

📖 路由器

use graphul::{http::Methods, Graphul};

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/", || async { "Home" });

    // you can use: Graphul::post, Graphul::put, Graphul::delete, Graphul::patch
    let route_get = Graphul::get("/hello", || async { "Hello, World 👋!" });

    // you can also use the `route` variable to add the route to the app
    app.add_router(route_get);

    app.run("127.0.0.1:8000").await;

💡 Graphul::router

use graphul::{
    Req,
    middleware::{self, Next},
    http::{response::Response,Methods},
    Graphul
};

async fn my_router() -> Graphul {
    let mut router = Graphul::router();

    router.get("/hi", || async {
        "Hey! :)"
    });
    // this middleware will be available only on this router
    router.middleware(middleware::from_fn(my_middleware));

    router
}

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/", || async {
        "hello world!"
    });

    app.add_router(my_router().await);

    app.run("127.0.0.1:8000").await;
}

📖 模板

use graphul::{
    http::Methods,
    Context, Graphul, template::HtmlTemplate,
};
use askama::Template;

#[derive(Template)]
#[template(path = "hello.html")]
struct HelloTemplate {
    name: String,
}

#[tokio::main]
async fn main() {
    let mut app = Graphul::new();

    app.get("/:name", |c: Context| async  move {
        let template = HelloTemplate { name: c.params("name") };
        HtmlTemplate(template)
    });

    app.run("127.0.0.1:8000").await;
}

许可证

本项目采用 MIT许可证

贡献

除非您明确声明,否则您有意向包含在 Graphul 中的任何贡献,都应按MIT许可,不附加任何额外条款或条件。

依赖项

~17MB
~375K SLoC