Giter VIP home page Giter VIP logo

graphul's Introduction

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]
async fn main() {
    let mut 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]
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;
}

๐Ÿ“– Resource

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;
}

๐Ÿ“– Static files

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;
}

๐ŸŒŸ static files with custom config

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;
}

๐Ÿ“– Groups

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;
}

๐Ÿ“– Share state

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;
}

๐Ÿ“– Share state with Resource

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;
}

๐Ÿ“– Middleware

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;
}

๐Ÿ“– Routers

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;
}

๐Ÿ“– Templates

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;
}

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.

graphul's People

Contributors

samuelbonilla avatar phosphorus-m avatar atticus64 avatar

Stargazers

Vippper avatar Diego Chavez avatar Bilal Barina avatar frans avatar Sergei avatar 0xNULL avatar Label avatar Juan David Carvajal Hernandez avatar  avatar  avatar mikione avatar Dmytro Momot avatar Yuki Toyoda avatar mahdi avatar 0w0 avatar Roomba, disciple of machine code avatar Ben Sparks avatar Jan Weinkauff avatar PH avatar  avatar J. Kitajima avatar SINHA Santos avatar Militch avatar RGBCube avatar fathularif avatar Syed Ather Rizvi avatar Kyoungjun Min avatar FuryFox avatar ฤamien โ„บazar avatar Suraj Mishra avatar Mohamed Ramadan avatar PRAMOD A JINGADE avatar James Edmonds avatar Konstantin avatar Jakepys avatar John Santhosh avatar jgj_c avatar Daniel Ceballos avatar Antonino Rossi avatar Kurobane avatar Aleksei Nepochatykh avatar Andres Londono avatar Richard Clayton avatar  avatar Santiago Fraire Willemoes avatar kirbylife avatar Adoankim avatar Nurul Abrar avatar James T avatar yuruiyin avatar  avatar  avatar Tung Do avatar Anish avatar Jeff Carpenter avatar  avatar Merlin avatar Samet Arฤฑk avatar Nguyen Huu Anh Tuan avatar Tobias Foerg avatar  avatar krovuxdev avatar  avatar Eduardo Flores avatar  avatar David avatar vikram mishra avatar VFLC avatar  avatar Christoph Grabo avatar  avatar Sandalots avatar Rui Chen avatar Carlos Rueda avatar austin wambugu avatar Xtian avatar Nguyแป…n Hแบฃi Nam avatar Shujaat Ali Khan avatar Billy Obregon  avatar Konstantin Bolshakov avatar Ivan Zhuravlev avatar  avatar Maxime Lestage avatar Christian Theilemann avatar Luis alberto Sinisterra muรฑoz avatar  avatar Darren Baldwin avatar Andrew Meier avatar Tafhim | JBM avatar Michael Edelman  avatar Georges KABBOUCHI avatar dalpei avatar swlkr avatar Steven Bower avatar Oscar Bailey avatar Nuttapong Maneenate avatar David Higginbotham avatar  avatar Sergio Martinez avatar Mike avatar

Watchers

Abhik Khanra avatar Suraj avatar  avatar  avatar Daniel Ceballos avatar Jonathan Solskov avatar James Sizeland avatar Jeyson Flores avatar Phi Nhรขn avatar

graphul's Issues

Middleware for individual/group routes

Is your feature request related to a problem? Please describe.
I'm not sure if it's already built-in, but I was wondering if it's possible to associate middlewares to an individual (or a group of) routes.

Describe the solution you'd like
I'd like to define middlewares that can be usable on individual/group routes rather than setting them up globally.

Describe alternatives you've considered
None at the moment

Additional context
A common use case (and the one which I stumbled upon recently) is about routes that require authentication along with the ones that don't. So for example, you have a bunch of public routes (eg: /*) and another bunch of private ones (eg: /admin/*). If I setup a middleware that checks authentication (and eventually redirects to a login page if the client is not authenticated) means that it'll act even to the public routes (and it'll create an endless loop which redirects to the login page).

What do you think? Thanks in advance for any feedback.

confusion with router api

for example, with axum, we can do this:

let app = Router::new()

i don't see anything related to routing in the docs. maybe it could be useful to have examples for routing as well.

Add Comparison & benchmarks to Readme

Thanks for your work.

Can I ask you the advantages over other routers? (Let's say axum or poem?)

I think the famous space called "Comparison" is missing in the Readme.

And benchmarks wouldn't be bad either.

๐Ÿ˜„

Error Deploy Shuttle

Describe the bug
I'll try the example of the documentation about how to deploy graphul in shuttle
Version of Graphul 0.4.5

To Reproduce
Steps to reproduce the behavior:

  1. Clone my repository on repo
  2. Build the project
  3. Try to deploy
  4. Get the next error

Expected behavior
I expect to succesfully deploiment but a savage error appears

Screenshots
image

Desktop

  • OS: Windows 10
  • Browser brave

Websockets?

Hello! I was building some examples and in the website I found this example:

async fn handle_socket(mut socket: WebSocket) {
  if let Some(msg) = socket.recv().await {
    if let Ok(msg) = msg {
      match msg {
        Message::Text(t) => {
          println!("client sent str: {:?}", t);
        }
        Message::Binary(_) => {
          println!("client sent binary data");
        }
        Message::Ping(_) => {
          println!("socket ping");
        }
        Message::Pong(_) => {
          println!("socket pong");
        }
        Message::Close(_) => {
          println!("client disconnected");
          return;
        }
      }
    } else {
        println!("client disconnected");
        return;
    }
  }

  loop {
    if socket
      .send(Message::Text(String::from("Hi!")))
      .await
      .is_err()
    {
      println!("client disconnected");
      return;
    }
    tokio::time::sleep(std::time::Duration::from_secs(3)).await;
  }
}

I found that the WebSocket struct doesn't exist so I wonder if this is a planned feature or a discarded feature. Thanks!

Middlewares not being applied

Describe the bug
Currently middlewares applied using the middleware method from a Graphul instance,
are initialized but are not being applied as part of consuming HTTP Requests.

use std::time::Duration;

use graphul::{http::Methods, Graphul, middleware::limit::RateLimitLayer};

#[tokio::main]
async fn main() {
  tracing_subscriber::fmt::init();

  let mut app = Graphul::new();

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

  app.middleware(RateLimitLayer::new(2, Duration::from_secs(100)));

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

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

To Reproduce
Steps to reproduce the behavior:

  1. Create an instance of Graphul similar to how its done above
  2. Apply a middleware of your choice (This PR contains a dumb middleware for testing)
  3. Check for logs on terminal

Expected behavior

The middleware is applied

Screenshots

N/A

Desktop (please complete the following information):

  • OS: macOS, Linux
  • Browser N/A
  • Version 0.5.5 (Forked from main on commit: 58b1cb2)

Smartphone (please complete the following information):
N/A

Additional context
N/A

How to do redirects?

I was wondering if there's a way to redirect requests rather than replying with HtmlTemplate or Json.

Thanks in advance, and congratulations for this interesting project!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.