| Crates.io | yahf |
| lib.rs | yahf |
| version | 0.0.2 |
| created_at | 2023-08-16 14:23:52.218354+00 |
| updated_at | 2023-10-19 20:46:39.793941+00 |
| description | Yet Another HTTP Framework focused on DX |
| homepage | |
| repository | https://github.com/lucasduartesobreira/yahf |
| max_upload_size | |
| id | 945961 |
| size | 152,287 |
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.
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();
}
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
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 fn handler1() -> ResponseBody {todo!()}
async fn handler2() -> Response<ResponseBody> {todo!()}
async fn handler3(req: RequestBody) -> ResponseBody {todo!()}
async fn handler4(req: Request<RequestBody>) -> ResponseBody {todo!()}
async fn handler5(req: RequestBody) -> Response<ResponseBody> {todo!()}
async fn handler6(req: Request<RequestBody>) -> Response<ResponseBody> {todo!()}
async fn handler7() -> Result<ResponseBody> {todo!()}
async fn handler8() -> Result<Response<ResponseBody>> {todo!()}
async fn handler9(req: Result<RequestBody>) -> Result<ResponseBody> {todo!()}
async fn handler10(req: Result<Request<RequestBody>>) -> Result<ResponseBody> {todo!()}
async fn handler11(req: Result<RequestBody>) -> Result<Response<ResponseBody>> {todo!()}
async fn handler12(req: Result<Request<RequestBody>>) -> Result<Response<ResponseBody>> {todo!()}
All these signatures comes from the implementations of RunnerInput and RunnerOutput.
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 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
Ok(req).into()
}
Err(err) => Err(err).into(),
}
}
// Handle any possible errors
async fn log_error(res: Result<Response
// 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
The repo includes illustrative examples demonstrating the integration of all the components
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: