Skip to content

Repository files navigation

Graphul

Graphul is an Express inspired web framework using a powerful extractor system. Designed to improve, speed, and scale your microservices with a friendly syntax, Graphul is built with Rust. that means Graphul gets memory safety, reliability, concurrency, and performance for free. helping to save money on infrastructure.

Discord Join our Discord server to chat with others in the Graphul community!

Install

Create a new project

$ cargo init hello-app
$ cd hello-app

Add graphul dependency

$ cargo add graphul

⚑️ Quickstart

use graphul::{Graphul, http::Methods};#[tokio::main]asyncfnmain(){letmut app = Graphul::new();
app.get("/", || async{"Hello, World πŸ‘‹!"});
app.run("127.0.0.1:8000").await;}

πŸ‘€ Examples

Listed below are some of the common examples. If you want to see more code examples , please visit our Examples Folder

common examples

πŸ›« Graphul vs most famous frameworks out there

Graphul

πŸ“– Context

use graphul::{http::Methods,Context,Graphul};#[tokio::main]asyncfnmain(){letmut app = Graphul::new();// /samuel?country=Colombia
app.get("/:name", |c:Context| asyncmove{/* 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]asyncfnmain(){letmut 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;}

πŸ“– Resource

use std::collections::HashMap;use graphul::{
async_trait,
extract::Json,
http::{resource::Resource, response::Response,StatusCode},Context,Graphul,IntoResponse,};use serde_json::json;typeResValue = HashMap<String,String>;structArticle;#[async_trait]implResourceforArticle{asyncfnget(c:Context) -> Response{let posts = json!({"posts":["Article 1","Article 2","Article ..."]});(StatusCode::OK, c.json(posts)).into_response()}asyncfnpost(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]asyncfnmain(){letmut app = Graphul::new();
app.resource("/article",Article);
app.run("127.0.0.1:8000").await;}

πŸ“– Static files

use graphul::{Graphul,FolderConfig,FileConfig};#[tokio::main]asyncfnmain(){letmut 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;}

🌟 static files with custom config

use graphul::{Graphul,FolderConfig,FileConfig};#[tokio::main]asyncfnmain(){letmut app = Graphul::new();
app.static_files("/","templates",FolderConfig{// single page applicationspa:false,// it support gzip, brotli and deflatecompress: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 deflatecompress:true,chunk_size:Some(65536)// buffer capacity 64KiB});
app.run("127.0.0.1:8000").await;}

πŸ“– Groups

use graphul::{
extract::{Path,Json},Graphul,
http::{Methods,StatusCode},IntoResponse};use serde_json::json;asyncfnindex() -> &'staticstr{"index handler"}asyncfnname(Path(name):Path<String>) -> implIntoResponse{let user = json!({"response": format!("my name is {}", name)});(StatusCode::CREATED,Json(user)).into_response()}#[tokio::main]asyncfnmain(){letmut app = Graphul::new();// GROUP /apiletmut api = app.group("api");// GROUP /api/userletmut user = api.group("user");// GET POST PUT DELETE ... /api/user
user.resource("/",Article);// GET /api/user/samuel
user.get("/:name", name);// GROUP /api/postletmut post = api.group("post");// GET /api/post
post.get("/", index);// GET /api/post/all
post.get("/all", || asyncmove{Json(json!({"message":"hello world!"}))});
app.run("127.0.0.1:8000").await;}

πŸ“– Share state

use graphul::{http::Methods, extract::State,Graphul};#[derive(Clone)]structAppState{data:String}#[tokio::main]asyncfnmain(){let state = AppState{data:"Hello, World πŸ‘‹!".to_string()};letmut app = Graphul::share_state(state);
app.get("/", |State(state):State<AppState>| async{
state.data});
app.run("127.0.0.1:8000").await;}

πŸ“– Share state with Resource

use graphul::{
async_trait,
http::{resource::Resource, response::Response,StatusCode},Context,Graphul,IntoResponse,};use serde_json::json;structArticle;#[derive(Clone)]structAppState{data:Vec<&'staticstr>,}#[async_trait]implResource<AppState>forArticle{asyncfnget(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]asyncfnmain(){let state = AppState{data:vec!["Article 1","Article 2","Article 3"],};letmut app = Graphul::share_state(state);
app.resource("/article",Article);
app.run("127.0.0.1:8000").await;}

πŸ“– Middleware

use graphul::{Req,
middleware::{self,Next},
http::{response::Response,Methods},Graphul};asyncfnmy_middleware(request:Req,next:Next) -> Response{// your logic
next.run(request).await}#[tokio::main]asyncfnmain(){letmut app = Graphul::new();
app.get("/", || async{"hello world!"});
app.middleware(middleware::from_fn(my_middleware));
app.run("127.0.0.1:8000").await;}

πŸ“– Routers

use graphul::{http::Methods,Graphul};#[tokio::main]asyncfn main(){letmut app = Graphul::new();
app.get("/", || async{"Home"});// you can use: Graphul::post, Graphul::put, Graphul::delete, Graphul::patchlet 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};asyncfnmy_router() -> Graphul{letmut 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]asyncfnmain(){letmut app = Graphul::new();
app.get("/", || async{"hello world!"});
app.add_router(my_router().await);
app.run("127.0.0.1:8000").await;}

πŸ“– Templates

use graphul::{
http::Methods,Context,Graphul, template::HtmlTemplate,};use askama::Template;#[derive(Template)]#[template(path = "hello.html")]structHelloTemplate{name:String,}#[tokio::main]asyncfnmain(){letmut app = Graphul::new();
app.get("/:name", |c:Context| asyncmove{let template = HelloTemplate{name: c.params("name")};HtmlTemplate(template)});
app.run("127.0.0.1:8000").await;}

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Graphul by you, shall be licensed as MIT, without any additional terms or conditions.

About

Optimize, speed, scale your microservices and save money πŸ’΅

Resources

Stars

452 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages