praxis_core/errors.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2024 Praxis Contributors
3
4//! Shared error types for the Praxis workspace.
5//!
6//! [`ProxyError`] is the primary error type, re-exported from `praxis_core`.
7
8use thiserror::Error;
9
10// -----------------------------------------------------------------------------
11// Errors
12// -----------------------------------------------------------------------------
13
14/// Errors that can occur during proxy operation.
15///
16/// ```
17/// use praxis_core::ProxyError;
18///
19/// let e = ProxyError::Config("bad yaml".into());
20/// assert_eq!(e.to_string(), "config: bad yaml");
21///
22/// let e = ProxyError::NoRoute("GET /missing".into());
23/// assert_eq!(e.to_string(), "no route for GET /missing");
24///
25/// let e = ProxyError::NoUpstream("backend".into());
26/// assert_eq!(e.to_string(), "no upstream in cluster 'backend'");
27/// ```
28#[derive(Debug, Error)]
29pub enum ProxyError {
30 /// Configuration loading or validation error.
31 ///
32 /// Raised during startup or hot-reload when YAML parsing or
33 /// validation fails. Not retriable; fix the configuration.
34 /// The server continues running with the previous config on
35 /// hot-reload failures.
36 #[error("config: {0}")]
37 Config(String),
38
39 /// No route matched the incoming request.
40 ///
41 /// Raised during request routing when no filter chain's
42 /// router matches the method, path, and headers. Returns
43 /// 404 to the client. Not retriable for the same request.
44 #[error("no route for {0}")]
45 NoRoute(String),
46
47 /// No upstream available in the given cluster.
48 ///
49 /// Raised when a route matched but all endpoints in the
50 /// target cluster are unhealthy or the cluster is empty.
51 /// Returns 503 to the client. Retriable after health checks
52 /// recover an endpoint.
53 #[error("no upstream in cluster '{0}'")]
54 NoUpstream(String),
55}
56
57// -----------------------------------------------------------------------------
58// Tests
59// -----------------------------------------------------------------------------
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn error_display() {
67 let e = ProxyError::Config("bad yaml".into());
68 assert_eq!(e.to_string(), "config: bad yaml", "Config error display mismatch");
69
70 let e = ProxyError::NoRoute("GET /missing".into());
71 assert_eq!(
72 e.to_string(),
73 "no route for GET /missing",
74 "NoRoute error display mismatch"
75 );
76
77 let e = ProxyError::NoUpstream("backend".into());
78 assert_eq!(
79 e.to_string(),
80 "no upstream in cluster 'backend'",
81 "NoUpstream error display mismatch"
82 );
83 }
84}