hashira/routing/
error_router.rs

1use crate::{components::AnyComponent, app::ErrorPageHandler};
2use http::StatusCode;
3use std::collections::HashMap;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7#[error("failed to insert error page for `{0}`, it already exists")]
8pub struct ErrorPageConflictError(StatusCode);
9
10/// Contains the error routes for the client.
11#[derive(Default, Clone, PartialEq)]
12pub struct ErrorRouter {
13    routes: HashMap<StatusCode, AnyComponent<serde_json::Value>>,
14    fallback: Option<AnyComponent<serde_json::Value>>,
15}
16
17impl ErrorRouter {
18    /// Constructs a new error router.
19    pub fn new() -> Self {
20        ErrorRouter {
21            routes: HashMap::new(),
22            fallback: None,
23        }
24    }
25
26    /// Adds a component for the given `StatusCode`.
27    pub fn insert(
28        &mut self,
29        status: StatusCode,
30        component: AnyComponent<serde_json::Value>,
31    ) -> Result<(), ErrorPageConflictError> {
32        if self.routes.insert(status, component).is_some() {
33            return Err(ErrorPageConflictError(status));
34        }
35
36        Ok(())
37    }
38
39    /// Adds a handler for any status code.
40    pub fn fallback(&mut self, component: AnyComponent<serde_json::Value>) {
41        self.fallback = Some(component);
42    }
43
44    /// Returns the component to render for the given `StatusCode`.
45    pub fn find(&self, status: &StatusCode) -> Option<&AnyComponent<serde_json::Value>> {
46        self.routes.get(status).or(self.fallback.as_ref())
47    }
48}
49
50/// Contains the error routes for the client.
51#[derive(Default)]
52pub struct ServerErrorRouter {
53    routes: HashMap<StatusCode, ErrorPageHandler>,
54    fallback: Option<ErrorPageHandler>,
55}
56
57impl ServerErrorRouter {
58    /// Constructs a new error router.
59    pub fn new() -> Self {
60        ServerErrorRouter {
61            routes: HashMap::new(),
62            fallback: None,
63        }
64    }
65
66    /// Adds a handler for the given `StatusCode`.
67    pub fn insert(
68        &mut self,
69        status: StatusCode,
70        handler: ErrorPageHandler,
71    ) -> Result<(), ErrorPageConflictError> {
72        if self.routes.insert(status, handler).is_some() {
73            return Err(ErrorPageConflictError(status));
74        }
75
76        Ok(())
77    }
78
79    /// Adds a component to handle for error status code.
80    pub fn fallback(&mut self, handler: ErrorPageHandler) {
81        self.fallback = Some(handler);
82    }
83
84    /// Returns the handler for the given `StatusCode`.
85    pub fn find(&self, status: &StatusCode) -> Option<&ErrorPageHandler> {
86        match self.routes.get(status) {
87            Some(handler) => Some(handler),
88            None => self.fallback.as_ref(),
89        }
90    }
91}