Rustgram
A lightweight, fast and easy to use http routing and middleware framework build on top of hyper
Features
- build routes and middleware like Tower services
- uses yaml files to define routes
Install in Cargo.toml
[]
# hyper when using Statuscode
= { = "0.14", = ["full"] }
# tokio for the async main fn
= { = "1", = ["full"] }
# rustgram
= "0.1"
Documentation
Getting started
- Create the router with a not found handler service (e.g. a function)
- adding routes, for every http method there is a router function: get, post, put, delete, head, ...
- use the r function to pass the handler to the router
- use the method function to define on what method this route should be matched to the given path
- set an url path
- enter the socket address to listen for connection
use StatusCode;
use ;
use SocketAddr;
async
pub async
async
Middleware
- A middleware is a service.
- The middleware calls the next service (which is obtained by the middleware transformation).
- A transform is used to return a new middleware with a next service
- The transform function is called everytime when a middleware is applied to a route
The middleware stack is build like a service call stack.
The Order of the middleware stack is reverse to the applied order.
use StatusCode;
use ;
use ;
//define a middleware service
//define a middleware transform
;
//or define a middleware transform with a function
async
pub async
//Apply a middleware to a route after the r function
async
Middleware with async handling
If work must be done before the req handling or after the response, a Box Future is needed
When calling async actions before the response, here Arc is needed to avoid lifetime issues:
- use a Pin Box feature
- use inner service as an arc pointer
- clone the arc pointer before calling the async block
- do the async action in the async block
use Future;
use Pin;
use Arc;
use ;
use ;
Only after response async action:
use Future;
use Pin;
use ;
use ;
Handler return and error handling
The router only uses Service traits. For normal functions and closure, this is already implemented.
The functions don't need to return a Hyper Response, but their return gets converted into hyper response.
Supported returns are:
- Hyper Response
- String
- &'static str
- Result<String, GramStdHttpErr>
- Result<String, E>
- Result<R, E>
The GramStdHttpErr gets converted into a hyper response.
IntoResponse can be implemented for every type. In this case it is implemented for an error.
If HttpErr is returned, it will be created in a Response from the Error.
use StatusCode;
use ;
use IntoResponse;
//example usage:
pub async
Result<R, E>
R can be any type which implements IntoResponse.
Example to return a json string:
use IntoResponse;
use Response;
use Serialize;
use to_string;
;
//in another file
use ;
;
pub async
Route builder and groups
- groups can only be build by the route builder
- the builder parses a yml file and create a new route file. this file contains a function which returns a router (to use it later).
- all routes in a route shares the same middleware and the same prefix
- nested groups are also possible
- Create a 2nd bin crate for the route builder.
- This crate calls the builder function
- Set the input and the output path (both relative to the current working directory)
- install rustgram with the route_builder feature
- Build and execute the route builder everytime the routes are changed
- use the route function, from the new file, to get the router
# in a workspace just create a new crate
cargo new route_builder
In the Cargo-toml file:
= { = "0.1", = ["route_builder"] }
Open the main function in src/main.rs
use route_parser;
Create the route file.
# define the namespace where the route handlers live
# or leave it empty and use the full path to the handler
base_handler: test_handler
# define the namespace for the middleware
base_mw: test_mw
# prefix for all routes
prefix: "/"
# the routes and groups. use the method followed by the path (p) and the handler (s)
routes:
- get:
p: ""
# must match the base_handler namespace
s: test_handler::test_handler
# a put route with middleware
- put:
p: ""
s: test_handler::test_handler
mw:
- mw1_transform
- mw_transform
# a group of routes.
# a prefix (p) for all routes and middleware (mw) like routes
- group:
p: admin
mw:
- mw1_transform
- mw_transform
# the routes to this group
gr:
- get:
p: ""
s: test_handler_db::test_handler_db_to_json
- get:
p: "/user/:id"
s: test_handler::test_handler
# for this route, mw is called first, then mw1, mw2 and mw3
- put:
p: "/many_mw"
s: test_handler::test_handler
mw:
- mw3_transform
- mw2_transform
- group:
p: nested
mw:
- mw1_transform
- mw_transform
gr:
# define a new group inside the group routes
- group:
p: "/management"
mw:
- mw1_transform
- mw_transform
gr:
- put:
p: "/put"
s: test_handler::test_handler
mw:
- mw5_transform
- mw4_transform
This file is parsed to this:
/**
# Generated route files by rustgram route builder.
Please do not modify this file. Any changes will be overridden by the next route build.
Use the returned router instead
*/
use ;
use crate*;
use crate*;
pub
//Now the route file can be used like this:
async