Struct cataclysm::Branch [−][src]
pub struct Branch<T> { /* fields omitted */ }
Expand description
Main cataclysm structure for route handling
Branches are cataclysm’s main building block. It is a really simple pattern matching system, with the following priorities. They are named branches to avoid conflict with the Branch extractor.
- Exact matching
- Pattern matching
- Default branches (a.k.a, variable handling in branches)
In the case of exact matching, the path constructor is pretty straight forward
let branch: Branch<()> = Branch::new("/hello/world");
Pattern matching is a bit more complex
// matches any route that starts with `/hello/` and then words of 3 or 4 letters, no numbers
let branch: Branch<()> = Branch::new("/hello/{regex:^[A-Za-z\\d]{3,4}$}");
Last but not least, we have variable detection, with no regex
// matches any route that contains "/hello/{:variable}"
let branch: Branch<()> = Branch::new("/hello/{:variable}");
Implementations
Creates a new branch
let branch: Branch<()> = Branch::new("/hello/world");
Adds a callback to a branch
This function is the main building block for callbacks in the branch. A MethodHandler consists of a Method, and a callback function. Se the Method structure to see how to construct them.
// Example index function
async fn index() -> Response {
Response::ok().body("hello")
}
// Branch that will reply go a get method in `/scope`
let branch: Branch<()> = Branch::new("/scope").with(Method::Get.to(index));
Adds a default method responder, in case no specific handler is found for the requested method.
By default, unmatched methods reply with a 405 Method Not Allowed
, but this function allows override of such behaviour.
let branch: Branch<()> = Branch::new("/").with(Method::Get.to(|| async {
Response::ok().body("Supported!")
})).unmatched_method_to(|| async {
Response::ok().body("Unsupported, please try with GET")
});
Adds a default callback, in case of no nested matching.
// This branch will reply in any of `/hello`, `/hello/world`, etc.
let branch: Branch<()> = Branch::new("/hello").defaults_to(|| async {
Response::ok().body("Are you lost?")
});
Merges two branches from their bases, in case you find it useful
let branch_1: Branch<()> = Branch::new("/hello/world");
let branch_2 = Branch::new("/hallo/welt");
// Replies to both branches, in theory
let merged_branch = branch_1.merge(branch_2);
Please note that the caller has precedence over the callee, so in case of layers, the layers of the left hand side will have precedence, as well as the regex matches and the variable callback.
Nests one branch in the top node of the first one
The “top node” is defined as the one following the path given to the branch constructor.
let to_be_nested: Branch<()> = Branch::new("/world");
// This one will reply in `/hello/world`
let branch = Branch::new("/hello").nest(to_be_nested);
Adds a processing layer to the callbacks contained in this branch
A layer is what is commonly known as middleware. The passed layer methods act as a wrap to the core handling functions of this branch. It is important to note that layer functions have a very specific structure: each one receives a Request
and a boxed Pipeline
. The function must return a pinned boxed future. A Timing Layer/Middleware function is provided as an example.
use cataclysm::{Branch, Additional, Pipeline, http::{Request, Response, Method}};
use futures::future::FutureExt;
use std::sync::Arc;
let branch = Branch::new("/hello")
.with(Method::Get.to(|| async {Response::ok().body("¡Hola!")}))
.layer(|req: Request, pipeline: Box<Pipeline<()>>, ad: Arc<Additional<()>>| async {
// Example of timing layer / middleware
let now = std::time::Instant::now();
// Execute the deeper layers of the pipeline, passing the request
let response = pipeline.execute(req, ad).await;
// Measure and print time
let elapsed = now.elapsed().as_nanos();
println!("Process time: {} ns", elapsed);
// We return the request for further possible processing.
response
}.boxed()
);
Calling the function multiple times will wrap the preceeding layer (or core handlers), like an onion 🧅.