Request context, (we call this “Rc” for short in starberry) is a struct consisting the Request Meta, Request Body, Request Stream, Response, locals and params.
As discussed in Chapter 4 and 5, we already know how to read data from request and send response. In this chapter we are going to focus more on Stream, locals and params.
Stream is a buffer reader, reading the TcpStream that the user send to the server. Since the RequestBody is lazy load, you may read the body on your own without relying on Starberry’s HttpBody. While it is technically possible to read data the user send after we receive the request, however this does not happen in Http1.1. Starberry will be able to handle Http2.0 response later on
For locals and params, they are 2 sets of data passing through Middleware Chain (which we are going to discuss later on).
Where params stores a value in the type-based params storage. Any previous value of the same type will be replaced.
You may do something like
// Store authentication information
req.set_param(User { id: 123, name: "Alice".to_string() });
// Store timing information
req.set_param(RequestTimer::start());
// In an authentication process. We do not write this syntax in actual middlewares
if let Some(user) = req.param::<User>() {
println!("Request by: {}", user.name);
// Proceed with authenticated user
} else {
return HttpResponse::unauthorized();
}
// Update a request timer
if let Some(timer) = req.param_mut::<RequestTimer>() {
timer.mark("after_db_query");
}
// Take ownership of a value
if let Some(token) = req.take_param::<AuthToken>() {
// Use and consume the token
validate_token(token);
}
To store data. No key is provided.
However for locals, it stores a value in the string-based locals storage with the given key. Any previous value with the same key will be replaced
req.set_local("user_id", 123);
req.set_local("is_premium", true);
req.set_local("cart_items", vec!["item1", "item2"]);
// In a request handler
if let Some(is_premium) = req.local::<bool>("is_premium") {
if *is_premium {
// Show premium content
}
}
// With different types
let user_id = req.local::<i32>("user_id");
let items = req.local::<Vec<String>>("cart_items");
// Modify a list of items
if let Some(items) = req.local_mut::<Vec<String>>("cart_items") {
items.push("new_item".to_string());
}
// Take ownership of a value
if let Some(token) = req.take_local::<String>("session_token") {
// Use and consume the token
validate_and_destroy_token(token);
}
Installing sbmstd to use starberry’s standard middleware library
In Chapter 1, we talked about starting a fairly application
pub static APP: SApp = once_cell::sync::Lazy::new(|| {
App::new().build()
});
Now let’s deep dive into setting configs, middlewares and settings in the application
The statement
App::new()
Initiates an AppBuilder instance. For the AppBuilder instance a set methods passing its owned value in while returning a modified owned value out is provided.
After manipulating and setting the variable into the AppBuilder, we use
AppBuilder::build()
To build and return a App instance. Once a APP instance is built, you are not allowed to change its config.
For example, in the Starberry example project the following code is provided
App::new()
.binding(String::from("127.0.0.1:1111"))
.mode(RunMode::Build)
.max_body_size(1024 * 1024 * 10)
.max_header_size(1024 * 10)
.append_middleware::<PrintLog>()
.append_middleware::<MyMiddleWare2>()
.insert_middleware::<MyMiddleWare1>()
.set_config("serect_key", "key")
.set_statics("static".to_string())
.build()
Let’s talk about each function
After that the APP is built and run