Expand description
YAHF is an web framework for Rust focused on developer experience, extensibility, and performance.
Nightly until
RPITIT
is stable
§Table of Contents
§Features
- Macro free Routing API
- Predictable error handling
- Native serialization and deserialization built into the handler
- Friendly syntax
§Example
The Hello world
of YAHF is:
use yahf::server::Server;
#[tokio::main]
async fn main() {
let server = Server::new().get(
"/",
|| async { "Hello world".to_string() },
&(),
&String::with_capacity(0),
);
server
.listen(([127, 0, 0, 1], 8000).into())
.await
.unwrap();
}
§Routing
Router
is used to bind handlers to paths.\
use yahf::router::Router;
// Router
let router = Router::new()
.get("/", root_get, &(), &())
.get("/foo", foo_get, &(), &())
.post("/foo", foo_post, &(), &())
.delete("/foo/bar", bar_delete, &(), &());
// calls respectively each of these handlers
async fn root_get() {}
async fn foo_get() {}
async fn foo_post() {}
async fn bar_delete() {}
Server
shares these features from Router
§Handlers
On YAHF, a handler
is a async function that is used to handle a Route
. An acceptable
handler
implements the trait Runner
. By default, these signatures are
supported:
use yahf::request::Request;
use yahf::response::Response;
async fn handler1() -> ResponseBody
async fn handler2() -> Response<ResponseBody>
async fn handler3(req: RequestBody) -> ResponseBody
async fn handler4(req: Request<RequestBody>) -> ResponseBody
async fn handler5(req: RequestBody) -> Response<ResponseBody>
async fn handler6(req: Request<RequestBody>) -> Response<ResponseBody>
async fn handler7() -> Result<ResponseBody>
async fn handler8() -> Result<Response<ResponseBody>>
async fn handler9(req: Result<RequestBody>) -> Result<ResponseBody>
async fn handler10(req: Result<Request<RequestBody>>) -> Result<ResponseBody>
async fn handler11(req: Result<RequestBody>) -> Result<Response<ResponseBody>>
async fn handler12(req: Result<Request<RequestBody>>) -> Result<Response<ResponseBody>>
All these signatures comes from the implementations of RunnerInput
and RunnerOutput
.
§Extensability
YAHF handlers
are modular by design. A handler
is decomposed into four modules: a body deserializer
,
a body serializer
, arguments
, and a response
.
These modules are glued together using the Runner
trait. Adding new
functionality to the handlers is just a matter of implementing one of these traits. For more
details, check the trait docs
§Middleware
Middleware
are async functions that will run previously or after a
handler
. These can really useful when combined with a Router
or a
Server
to reuse logic and create "pipelines"
.
use serde::Deserialize;
use serde::Serialize;
use yahf::handler::Json;
use yahf::request::Request;
use yahf::result::Result;
use yahf::response::Response;
use yahf::router::Router;
use yahf::server::Server;
struct ComputationBody
// Print the time, the method, and the path from the Request
async fn log_middleware(req: Result<Request<String>>) -> Result<Request<String>>
// Handle any possible errors
async fn log_error(res: Result<Response<String>>) -> Result<Response<String>>
// Compute something using the ComputationBody
async fn some_computation(req: ComputationBody) -> ComputationBody
// Set a [`Router`](router::Router) with both `Middlewares`.
// The route `/` will become: `log_middleware -> some_computation -> log_middleware`
let router = Router::new()
.pre(log_middleware)
.after(log_error)
.get("/", some_computation, &Json::new(), &Json::new());
More of this example here
§Examples
The repo includes illustrative examples demonstrating the integration of all the components
Modules§
- handler
- Async functions that are used to handle requests
- middleware
- Async functions that runs before or after the handler
- request
- Newtype of Request
- response
- NewType of Response
- result
- NewType of Result
- router
- Struct to help with binding handlers to paths and Middlewares
- server
- Struct to setup and run the HTTP Server