redirects, middleware, Transport, set/capture error status (#4751)
* wip: redirect * redirect example * fix file upload not in a form * wip * deny missing cfgs * wip: add router fallback but it's not working * fix suspense bug after rebuilds that queued work * more cleanup * add test for error codes * add helpful comment * bring back middleware annotation * fix cfg * add server feature * fix doctest * just disable liveview test for now * fix liveview * dont send init * cache more playwright! * add more pkgs to cache
This commit is contained in:
1 parent
8a81475ba8
commit
9243ef4128
35 files changed
+935
-800
No files matched your search
@@ -0,0 +1,40 @@
|
||||
// @ts-check
|
||||
const { test, expect } = require("@playwright/test");
|
||||
|
||||
test("errors", async ({ page }) => {
|
||||
// Make sure going to home returns a 200
|
||||
const res = await page.goto("http://localhost:8124");
|
||||
if (!res) {
|
||||
throw new Error("Failed to navigate to http://localhost:8124");
|
||||
}
|
||||
|
||||
expect(res.status()).toBe(200);
|
||||
|
||||
// Go to /blog/1 which should also be okay
|
||||
const blogRes = await page.goto("http://localhost:8124/blog/1");
|
||||
if (!blogRes) {
|
||||
throw new Error("Failed to navigate to http://localhost:8124/blog/1");
|
||||
}
|
||||
expect(blogRes.status()).toBe(200);
|
||||
|
||||
// Go to /blog/2 which should be a 201
|
||||
const blogErrorRes = await page.goto("http://localhost:8124/blog/2");
|
||||
if (!blogErrorRes) {
|
||||
throw new Error("Failed to navigate to http://localhost:8124/blog/2");
|
||||
}
|
||||
expect(blogErrorRes.status()).toBe(201);
|
||||
|
||||
// Go to /blog/3 which should be a 500
|
||||
const blogPanicRes = await page.goto("http://localhost:8124/blog/3");
|
||||
if (!blogPanicRes) {
|
||||
throw new Error("Failed to navigate to http://localhost:8124/blog/3");
|
||||
}
|
||||
expect(blogPanicRes.status()).toBe(500);
|
||||
|
||||
// Go to /blog/4 which should be a 404
|
||||
const blogNotFoundRes = await page.goto("http://localhost:8124/blog/4");
|
||||
if (!blogNotFoundRes) {
|
||||
throw new Error("Failed to navigate to http://localhost:8124/blog/4");
|
||||
}
|
||||
expect(blogNotFoundRes.status()).toBe(404);
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
.dioxus
|
||||
dist
|
||||
target
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "dioxus-playwright-fullstack-error-codes-test"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dioxus = { workspace = true, features = ["fullstack", "router"] }
|
||||
|
||||
[features]
|
||||
default = ["server", "web"]
|
||||
server = ["dioxus/server"]
|
||||
web = ["dioxus/web"]
|
||||
@@ -0,0 +1,80 @@
|
||||
//! To render custom error pages, you can create a layout component that captures errors from routes
|
||||
//! with an `ErrorBoundary` and display different content based on the error type.
|
||||
//!
|
||||
//! While capturing the error, we set the appropriate HTTP status code using `FullstackContext::commit_error_status`.
|
||||
//! The router will then use this status code when doing server-side rendering (SSR).
|
||||
//!
|
||||
//! Any errors not captured by an error boundary will be handled by dioxus-ssr itself, which will render
|
||||
//! a generic error page instead.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_fullstack::{FullstackContext, StatusCode};
|
||||
|
||||
fn main() {
|
||||
dioxus::launch(|| {
|
||||
rsx! {
|
||||
Router::<Route> {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Routable, PartialEq, Clone, Debug)]
|
||||
enum Route {
|
||||
#[layout(ErrorLayout)]
|
||||
#[route("/")]
|
||||
Home,
|
||||
|
||||
#[route("/blog/:id")]
|
||||
Blog { id: u32 },
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Home() -> Element {
|
||||
rsx! {
|
||||
div { "Welcome to the home page!" }
|
||||
div { display: "flex", flex_direction: "column",
|
||||
Link { to: Route::Blog { id: 1 }, "Go to blog post 1" }
|
||||
Link { to: Route::Blog { id: 2 }, "Go to blog post 2 (201)" }
|
||||
Link { to: Route::Blog { id: 3 }, "Go to blog post 3 (error)" }
|
||||
Link { to: Route::Blog { id: 4 }, "Go to blog post 4 (not found)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Blog(id: u32) -> Element {
|
||||
match id {
|
||||
1 => rsx! { div { "Blog post 1" } },
|
||||
2 => {
|
||||
FullstackContext::commit_http_status(StatusCode::CREATED, None);
|
||||
rsx! { div { "Blog post 2" } }
|
||||
}
|
||||
3 => dioxus_core::bail!("An error occurred while loading the blog post!"),
|
||||
_ => HttpError::not_found("Blog post not found")?,
|
||||
}
|
||||
}
|
||||
|
||||
/// In our `ErrorLayout` component, we wrap the `Outlet` in an `ErrorBoundary`. This lets us attempt
|
||||
/// to downcast the error to an `HttpError` and set the appropriate status code.
|
||||
///
|
||||
/// The `commit_error_status` function will attempt to downcast the error to an `HttpError` and
|
||||
/// set the status code accordingly. Note that you can commit any status code you want with `commit_http_status`.
|
||||
///
|
||||
/// The router will automatically set the HTTP status code when doing SSR.
|
||||
#[component]
|
||||
fn ErrorLayout() -> Element {
|
||||
rsx! {
|
||||
ErrorBoundary {
|
||||
handle_error: move |err: ErrorContext| {
|
||||
let http_error = FullstackContext::commit_error_status(err.error().unwrap());
|
||||
match http_error.status {
|
||||
StatusCode::NOT_FOUND => rsx! { div { "404 - Page not found" } },
|
||||
StatusCode::UNAUTHORIZED => rsx! { div { "401 - Unauthorized" } },
|
||||
StatusCode::INTERNAL_SERVER_ERROR => rsx! { div { "500 - Internal Server Error" } },
|
||||
_ => rsx! { div { "An unknown error occurred" } },
|
||||
}
|
||||
},
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// This test is used by playwright configured in the root of the repo
|
||||
|
||||
use axum::{extract::ws::WebSocketUpgrade, response::Html, routing::get, Router};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus::{logger::tracing::Level, prelude::*};
|
||||
|
||||
fn app() -> Element {
|
||||
let mut num = use_signal(|| 0);
|
||||
@@ -40,6 +40,8 @@ fn OnMounted() -> Element {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
_ = dioxus::logger::init(Level::DEBUG);
|
||||
|
||||
let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
|
||||
|
||||
let view = dioxus_liveview::LiveViewPool::new();
|
||||
|
||||
@@ -215,5 +215,14 @@ module.exports = defineConfig({
|
||||
reuseExistingServer: !process.env.CI,
|
||||
stdout: "pipe",
|
||||
},
|
||||
{
|
||||
cwd: path.join(process.cwd(), "fullstack-error-codes"),
|
||||
command:
|
||||
'cargo run --package dioxus-cli --release -- run --force-sequential --addr "127.0.0.1" --port 8124',
|
||||
port: 8124,
|
||||
timeout: 50 * 60 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
stdout: "pipe",
|
||||
},
|
||||
],
|
||||
});
|
||||
Reference in new issue
Block a user