This version of the documentation is outdated, and features documented here may work differently now. You can see the latest stable version of the docs here.
Request State
While build-time strategies fulfill many use-cases, there are also scenarios in which you may need access to information only available at request-time, like an authentication key that the client sends over HTTP as a cookie. For these cases, Perseus supports the request state strategy, which is akin to traditional server-side rendering, whereby you render the page when a client requests it.
If you can avoid this strategy, do, because it will bring your app's TTFB (time to first byte) down, remember that anything done in this strategy is done on the server while the client is waiting for a page.
Usage
Here's an example taken from here of using this strategy to tell the user their own IP address (albeit not hugely reliably as this header can be trivially spoofed, but this is for demonstration purposes):
use perseus::{RenderFnResultWithCause, Request, Template};
use sycamore::prelude::{view, Html, View};
#[perseus::make_rx(PageStateRx)]
pub struct PageState {
ip: String,
}
#[perseus::template_rx]
pub fn request_state_page(state: PageStateRx) -> View<G> {
view! {
p {
(
format!("Your IP address is {}.", state.ip.get())
)
}
}
}
pub fn get_template<G: Html>() -> Template<G> {
Template::new("request_state")
.request_state_fn(get_request_state)
.template(request_state_page)
}
#[perseus::autoserde(request_state)]
pub async fn get_request_state(
_path: String,
_locale: String,
// Unlike in build state, in request state we get access to the information that the user sent with their HTTP request
// IN this example, we extract the browser's reporting of their IP address and display it to them
req: Request,
) -> RenderFnResultWithCause<PageState> {
Ok(PageState {
ip: format!(
"{:?}",
req.headers()
// NOTE: This header can be trivially spoofed, and may well not be the user's actual IP address
.get("X-Forwarded-For")
.unwrap_or(&perseus::http::HeaderValue::from_str("hidden from view!").unwrap())
),
})
}
Note that, just like build state, this strategy generates stringified properties that will be passed to the page to render it (serialization is handled by The web frameworks Perseus supports automatically pass this information to handlers like Perseus. The slightly difficult thing is then converting this from their custom format to Perseus' (which is just an alias for the #[perseus::autoserde(request_state)]
), and it also uses RenderFnWithCause
(see the section on build state for more information). The key difference though is that this strategy receives a second, very powerful parameter: the HTTP request that the user sent (perseus::Request
).How do you get the user's request information?
http
module's). This is done in the appropriate server integration crate.
That parameter is actually just an alias for this, which gives you access to all manner of things in the user's HTTP request. The main one we're concerned with in this example though is X-Forwarded-For
, which contains the user's IP address (unless it's trivially spoofed). Because we can't assume that any HTTP header exists, we fall back to a message saying the IP address is hidden if we can't access the header.