{"id":13502916,"url":"https://github.com/graphul-rs/graphul","last_synced_at":"2025-12-12T13:46:14.230Z","repository":{"id":61059602,"uuid":"447034562","full_name":"graphul-rs/graphul","owner":"graphul-rs","description":"Optimize, speed, scale your microservices and save money 💵","archived":false,"fork":false,"pushed_at":"2023-09-25T19:27:53.000Z","size":6134,"stargazers_count":449,"open_issues_count":0,"forks_count":9,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-03-06T07:18:10.643Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://graphul-rs.github.io/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphul-rs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":["samuelbonilla"],"patreon":"samuelbonilla"}},"created_at":"2022-01-12T01:18:35.000Z","updated_at":"2025-02-11T11:17:29.000Z","dependencies_parsed_at":"2022-10-09T09:28:11.741Z","dependency_job_id":"2b620f65-9c7f-4eaa-bb6b-f4bb688655f7","html_url":"https://github.com/graphul-rs/graphul","commit_stats":{"total_commits":108,"total_committers":5,"mean_commits":21.6,"dds":0.5925925925925926,"last_synced_commit":"58b1cb24ffdcec7693233f62d988c17eb8cae1f2"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphul-rs%2Fgraphul","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphul-rs%2Fgraphul/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphul-rs%2Fgraphul/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphul-rs%2Fgraphul/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphul-rs","download_url":"https://codeload.github.com/graphul-rs/graphul/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246187190,"owners_count":20737459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T22:02:30.051Z","updated_at":"2025-12-12T13:46:09.189Z","avatar_url":"https://github.com/graphul-rs.png","language":"Rust","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/rustful-rs/rustful\"\u003e\n    \u003cimg alt=\"Graphul\" height=\"200\" src=\"./img/logo.png\"\u003e\n  \u003c/a\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n\u003cb\u003eGraphul\u003c/b\u003e is an \u003ca href=\"https://github.com/expressjs/express\"\u003eExpress\u003c/a\u003e inspired \u003cb\u003eweb framework\u003c/b\u003e using a powerful extractor system. Designed to improve, speed, and scale your microservices with a friendly syntax, Graphul is built with \u003ca href=\"https://www.rust-lang.org/\"\u003eRust\u003c/a\u003e. that means Graphul gets memory safety, reliability, concurrency, and performance for free. helping to save money on infrastructure.\n\u003c/p\u003e\n\n\n## [Buy a Coffee with Bitcoin ☕️](https://github.com/graphul-rs/graphul/blob/main/BUY-A-COFFEE.md)\n\n[![Discord](https://img.shields.io/discord/1096163462767444130?label=Discord)](https://discord.gg/3WCMgT3KCS)\nJoin our Discord server to chat with others in the Graphul community!\n\n## Install\n\n#### Create a new project\n```\n$ cargo init hello-app\n\n$ cd hello-app\n```\n\n\n#### Add graphul dependency\n\n```\n$ cargo add graphul\n```\n\n## ⚡️ Quickstart\n\n```rust\nuse graphul::{Graphul, http::Methods};\n\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/\", || async {\n        \"Hello, World 👋!\"\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 👀 Examples\n\nListed below are some of the common examples. If you want to see more code examples , please visit our [Examples Folder](https://github.com/graphul-rs/graphul/tree/main/examples)\n\n## common examples\n\n- [Context](#-context)\n- [JSON](#-json)\n- [Resource](#-resource)\n- [Static files](#-static-files)\n- [Groups](#-groups)\n- [Share state](#-share-state)\n- [Share state with Resource](#-share-state-with-resource)\n- [Middleware](#-middleware)\n- [Routers](#-routers)\n- [Templates](#-templates)\n- [Swagger - OpenAPI](https://github.com/graphul-rs/graphul/tree/main/examples/utoipa-swagger-ui)\n- ⭐️ help us by adding a star on [GitHub Star](https://github.com/graphul-rs/graphul/stargazers) to the project\n\n## 🛫 Graphul vs most famous frameworks out there\n\n\u003cimg alt=\"Graphul\" width=\"700\" src=\"./img/compare.png\"\u003e\n\n## 📖 Context\n\n```rust\nuse graphul::{http::Methods, Context, Graphul};\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    // /samuel?country=Colombia\n    app.get(\"/:name\", |c: Context| async move {\n        /*\n           statically typed query param extraction\n           let value: Json\u003cMyType\u003e = match c.parse_params().await\n           let value: Json\u003cMyType\u003e = match c.parse_query().await\n        */\n\n        let name = c.params(\"name\");\n        let country = c.query(\"country\");\n        let ip = c.ip();\n\n        format!(\"My name is {name}, I'm from {country}, my IP is {ip}\",)\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 JSON\n\n```rust\nuse graphul::{Graphul, http::Methods, extract::Json};\nuse serde_json::json;\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/\", || async {\n        Json(json!({\n            \"name\": \"full_name\",\n            \"age\": 98,\n            \"phones\": [\n                format!(\"+44 {}\", 8)\n            ]\n        }))\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Resource\n\n```rust\nuse std::collections::HashMap;\n\nuse graphul::{\n    async_trait,\n    extract::Json,\n    http::{resource::Resource, response::Response, StatusCode},\n    Context, Graphul, IntoResponse,\n};\nuse serde_json::json;\n\ntype ResValue = HashMap\u003cString, String\u003e;\n\nstruct Article;\n\n#[async_trait]\nimpl Resource for Article {\n    async fn get(c: Context) -\u003e Response {\n        let posts = json!({\n            \"posts\": [\"Article 1\", \"Article 2\", \"Article ...\"]\n        });\n        (StatusCode::OK, c.json(posts)).into_response()\n    }\n\n    async fn post(c: Context) -\u003e Response {\n        // you can use ctx.parse_params() or ctx.parse_query()\n        let value: Json\u003cResValue\u003e = match c.payload().await {\n            Ok(data) =\u003e data,\n            Err(err) =\u003e return err.into_response(),\n        };\n\n        (StatusCode::CREATED, value).into_response()\n    }\n\n    // you can use put, delete, head, patch and trace\n}\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.resource(\"/article\", Article);\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Static files\n\n```rust\nuse graphul::{Graphul, FolderConfig, FileConfig};\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    // path = \"/static\", dir = public\n    app.static_files(\"/static\", \"public\", FolderConfig::default());\n\n    // single page application\n    app.static_files(\"/\", \"app/build\", FolderConfig::spa());\n\n    app.static_file(\"/about\", \"templates/about.html\", FileConfig::default());\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n### 🌟 static files with custom config\n\n```rust\nuse graphul::{Graphul, FolderConfig, FileConfig};\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.static_files(\"/\", \"templates\", FolderConfig {\n        // single page application\n        spa: false,\n        // it support gzip, brotli and deflate\n        compress: true,\n        // Set a specific read buffer chunk size.\n        // The default capacity is 64kb.\n        chunk_size: None,\n        // If the requested path is a directory append `index.html`.\n        // This is useful for static sites.\n        index: true,\n        // fallback - This file will be called if there is no file at the path of the request.\n        not_found: Some(\"templates/404.html\"), // or None\n    });\n\n    app.static_file(\"/path\", \"templates/about.html\", FileConfig {\n        // it support gzip, brotli and deflate\n        compress: true,\n        chunk_size: Some(65536) // buffer capacity 64KiB\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Groups\n\n\n```rust\nuse graphul::{\n    extract::{Path, Json},\n    Graphul,\n    http::{ Methods, StatusCode }, IntoResponse\n};\n\nuse serde_json::json;\n\nasync fn index() -\u003e \u0026'static str {\n    \"index handler\"\n}\n\nasync fn name(Path(name): Path\u003cString\u003e) -\u003e impl IntoResponse {\n    let user = json!({\n        \"response\": format!(\"my name is {}\", name)\n    });\n    (StatusCode::CREATED, Json(user)).into_response()\n}\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    // GROUP /api\n    let mut api = app.group(\"api\");\n\n    // GROUP /api/user\n    let mut user = api.group(\"user\");\n\n    // GET POST PUT DELETE ... /api/user\n    user.resource(\"/\", Article);\n\n    // GET /api/user/samuel\n    user.get(\"/:name\", name);\n\n    // GROUP /api/post\n    let mut post = api.group(\"post\");\n\n    // GET /api/post\n    post.get(\"/\", index);\n\n    // GET /api/post/all\n    post.get(\"/all\", || async move {\n        Json(json!({\"message\": \"hello world!\"}))\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Share state\n\n```rust\nuse graphul::{http::Methods, extract::State, Graphul};\n\n#[derive(Clone)]\nstruct AppState {\n    data: String\n}\n\n#[tokio::main]\nasync fn main() {\n    let state = AppState { data: \"Hello, World 👋!\".to_string() };\n    let mut app = Graphul::share_state(state);\n\n    app.get(\"/\", |State(state): State\u003cAppState\u003e| async {\n        state.data\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Share state with Resource\n\n```rust\nuse graphul::{\n    async_trait,\n    http::{resource::Resource, response::Response, StatusCode},\n    Context, Graphul, IntoResponse,\n};\nuse serde_json::json;\n\nstruct Article;\n\n#[derive(Clone)]\nstruct AppState {\n    data: Vec\u003c\u0026'static str\u003e,\n}\n\n#[async_trait]\nimpl Resource\u003cAppState\u003e for Article {\n\n    async fn get(ctx: Context\u003cAppState\u003e) -\u003e Response {\n        let article = ctx.state();\n\n        let posts = json!({\n            \"posts\": article.data,\n        });\n        (StatusCode::OK, ctx.json(posts)).into_response()\n    }\n\n    // you can use post, put, delete, head, patch and trace\n\n}\n\n#[tokio::main]\nasync fn main() {\n    let state = AppState {\n        data: vec![\"Article 1\", \"Article 2\", \"Article 3\"],\n    };\n    let mut app = Graphul::share_state(state);\n\n    app.resource(\"/article\", Article);\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Middleware\n\n- [Example using tracing](https://github.com/graphul-rs/graphul/tree/main/examples/tracing-middleware)\n\n```rust\nuse graphul::{\n    Req,\n    middleware::{self, Next},\n    http::{response::Response,Methods},\n    Graphul\n};\n\nasync fn my_middleware( request: Req, next: Next ) -\u003e Response {\n\n    // your logic\n\n    next.run(request).await\n}\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/\", || async {\n        \"hello world!\"\n    });\n    app.middleware(middleware::from_fn(my_middleware));\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Routers\n\n- [Example Multiple Routers](https://github.com/graphul-rs/graphul/tree/main/examples/multiple-routers)\n\n```rust\nuse graphul::{http::Methods, Graphul};\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/\", || async { \"Home\" });\n\n    // you can use: Graphul::post, Graphul::put, Graphul::delete, Graphul::patch\n    let route_get = Graphul::get(\"/hello\", || async { \"Hello, World 👋!\" });\n\n    // you can also use the `route` variable to add the route to the app\n    app.add_router(route_get);\n\n    app.run(\"127.0.0.1:8000\").await;\n```\n\n#### 💡 Graphul::router\n\n```rust\nuse graphul::{\n    Req,\n    middleware::{self, Next},\n    http::{response::Response,Methods},\n    Graphul\n};\n\nasync fn my_router() -\u003e Graphul {\n    let mut router = Graphul::router();\n\n    router.get(\"/hi\", || async {\n        \"Hey! :)\"\n    });\n    // this middleware will be available only on this router\n    router.middleware(middleware::from_fn(my_middleware));\n\n    router\n}\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/\", || async {\n        \"hello world!\"\n    });\n\n    app.add_router(my_router().await);\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## 📖 Templates\n\n```rust\nuse graphul::{\n    http::Methods,\n    Context, Graphul, template::HtmlTemplate,\n};\nuse askama::Template;\n\n#[derive(Template)]\n#[template(path = \"hello.html\")]\nstruct HelloTemplate {\n    name: String,\n}\n\n#[tokio::main]\nasync fn main() {\n    let mut app = Graphul::new();\n\n    app.get(\"/:name\", |c: Context| async  move {\n        let template = HelloTemplate { name: c.params(\"name\") };\n        HtmlTemplate(template)\n    });\n\n    app.run(\"127.0.0.1:8000\").await;\n}\n```\n\n## License\n\nThis project is licensed under the [MIT license](https://github.com/graphul-rs/graphul/blob/main/LICENSE).\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in `Graphul` by you, shall be licensed as MIT, without any\nadditional terms or conditions.\n","funding_links":["https://github.com/sponsors/samuelbonilla","https://patreon.com/samuelbonilla"],"categories":["Libraries","库 Libraries","Rust"],"sub_categories":["Web programming","网络编程 Web programming"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphul-rs%2Fgraphul","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphul-rs%2Fgraphul","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphul-rs%2Fgraphul/lists"}