Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/graphul-rs/graphul
Optimize, speed, scale your microservices and save money π΅
https://github.com/graphul-rs/graphul
Last synced: about 1 month ago
JSON representation
Optimize, speed, scale your microservices and save money π΅
- Host: GitHub
- URL: https://github.com/graphul-rs/graphul
- Owner: graphul-rs
- License: mit
- Created: 2022-01-12T01:18:35.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-09-25T19:27:53.000Z (about 1 year ago)
- Last Synced: 2024-10-08T10:12:02.887Z (2 months ago)
- Language: Rust
- Homepage: https://graphul-rs.github.io/
- Size: 5.85 MB
- Stars: 445
- Watchers: 9
- Forks: 11
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
- awesome-rust - Graphul - inspired web framework. [![crate](https://img.shields.io/crates/v/create-rust-app.svg)](https://crates.io/crates/graphul) (Libraries / Web programming)
- awesome-rust-cn - Graphul - inspired (εΊ Libraries / η½η»ηΌη¨ Web programming)
README
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.## [Buy a Coffee with Bitcoin βοΈ](https://github.com/graphul-rs/graphul/blob/main/BUY-A-COFFEE.md)
[![Discord](https://img.shields.io/discord/1096163462767444130?label=Discord)](https://discord.gg/3WCMgT3KCS)
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
```rust
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](https://github.com/graphul-rs/graphul/tree/main/examples)
## common examples
- [Context](#-context)
- [JSON](#-json)
- [Resource](#-resource)
- [Static files](#-static-files)
- [Groups](#-groups)
- [Share state](#-share-state)
- [Share state with Resource](#-share-state-with-resource)
- [Middleware](#-middleware)
- [Routers](#-routers)
- [Templates](#-templates)
- [Swagger - OpenAPI](https://github.com/graphul-rs/graphul/tree/main/examples/utoipa-swagger-ui)
- βοΈ help us by adding a star on [GitHub Star](https://github.com/graphul-rs/graphul/stargazers) to the project## π« Graphul vs most famous frameworks out there
## π Context
```rust
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 = match c.parse_params().await
let value: Json = 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
```rust
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
```rust
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;
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 = 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
```rust
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
```rust
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
```rust
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) -> 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
```rust
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| async {
state.data
});app.run("127.0.0.1:8000").await;
}
```## π Share state with Resource
```rust
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 for Article {async fn get(ctx: Context) -> 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
- [Example using tracing](https://github.com/graphul-rs/graphul/tree/main/examples/tracing-middleware)
```rust
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
- [Example Multiple Routers](https://github.com/graphul-rs/graphul/tree/main/examples/multiple-routers)
```rust
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
```rust
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
```rust
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](https://github.com/graphul-rs/graphul/blob/main/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.