Warning: YAHF works only on nightly until
RPITITis stable
The goal of YAHF is both to provide a good developer experience and to be easy to extend.
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 Server;
async
Routing
Router is used to bind handlers to paths.\
use Router;
// Router
let router = new
.get
.get
.post
.delete;
// calls respectively each of these handlers
async
async
async
async
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:
async
async
async
async
async
async
async
async
async
async
async
async
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 std::time; use std::time::UNIX_EPOCH; #[derive(Debug, Deserialize, Serialize)] struct ComputationBody { value: u32, }
// Print the time, the method, and the path from the Request async fn log_middleware(req: Result<Request>) -> Result<Request> { match req.into_inner() { Ok(req) => { println!( "{} - {} - {}", time::SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Negative time") .as_millis(), req.method().as_str(), req.uri().path() );
Ok(req).into()
}
Err(err) => Err(err).into(),
}
}
// Handle any possible errors async fn log_error(res: Result<Response>) -> Result<Response> { match res.into_inner() { Err(err) => { println!( "{} - {}", time::SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Negative time") .as_millis(), err.code(), ); Err(err).into() } ok => ok.into(), } }
// Compute something using the ComputationBody async fn some_computation(req: ComputationBody) -> ComputationBody { ComputationBody { value: req.value + 1, } }
// Set a 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
Goals for v1.0.0
YAHFfollows theSemVer.
The objective for v1.0.0 is to have a stable project that can deal with real-world problems with good developer experience and the possibility to extend the project to suit any need.
The goal features for this version are:
- Composable routing system;
- Middleware functions;
- HTTP/1.1 with or without security.