Allow returning HTTP STATUS in fullstack
Problem
Discord reference Steps To Reproduce Given a route
#[derive(Clone, Routable, PartialEq, Serialize, Deserialize)]
enum Route {
#[route("/product/:url_slug")]
Product { url_slug: String },
}
and a component Product where it takes a url and fetch a product by THAT url. It is normal for that to failed due to unrecognised urls. In those case, it would be HTTP 404 NOT FOUND.
#[component]
fn Product(url_slug: String) -> Element {
let product = use_resource(|| async {
get_product().await
});
rsx! { }
}
The advised solution is to try server_context, however, that doesn't seem to work.
#[server]
async fn get_product() -> Result<String, ServerFnError> {
if let Ok(mut resp) = server_context().response_parts_mut() {
resp.status = StatusCode::NOT_FOUND;
Err(ServerFnError::Response("404 NOT FOUND".into()))
} else {
Ok(
"A dummy product".to_string()
)
}
}
Expected behavior The first request in the below screenshot should return 404(or whatever that was returned from the function. For the second AJAX call, that should behave the same?
Screenshots
Environment:
- Dioxus version: 0.5
- Rust version: 1.80
- OS info: Debian
- App platform: fullstack
The fact that setting the status happens after some async work makes this complicated. Fullstack now supports streaming which means there are a few different stages of the response:
Before any content is sent
Fullstack needs to choose chat response is sent to the client. Once the status is sent, it cannot be changed (mostly - we can send an incomplete streaming chunk to fail even after we send a 200 response)
Before the body is started
Fullstack needs to insert any <head> content that should be available for SEO. <head> elements can be streamed in after this, but they may not be visible for SEO
After the body is started
Fullstack can only modify the head and body through javascript. Any text content should still be visible for SEO, but it may not be in the right order
How fullstack should handle this
I was talking with Jon about this, and we came up with this order:
- Initially fullstack waits and accumulates contents without sending any response
- Once the suspense boundary that contains the
Routerrenders, fullstack sets the status and renders the head - Each new suspense boundary is streamed in like normal