Skip to main content

apollo_errors/
error.rs

1//! Core Error trait definition
2
3/// Extract the diagnostic code from a `miette::Diagnostic` as a string.
4///
5/// Returns `"UNKNOWN_ERROR"` if no code is present.
6#[inline]
7pub fn diagnostic_code<D: miette::Diagnostic + ?Sized>(diagnostic: &D) -> String {
8    diagnostic
9        .code()
10        .map(|c| c.to_string())
11        .unwrap_or_else(|| "UNKNOWN_ERROR".to_string())
12}
13
14/// Extract the help text from a `miette::Diagnostic` as an optional string.
15#[inline]
16pub fn diagnostic_help<D: miette::Diagnostic + ?Sized>(diagnostic: &D) -> Option<String> {
17    diagnostic.help().map(|h| h.to_string())
18}
19
20/// The core trait for apollo errors.
21///
22/// This trait extends `std::error::Error` and `miette::Diagnostic`
23/// to provide multi-format rendering.
24///
25/// # Derive Macro
26///
27/// Use `#[derive(apollo_errors::Error)]` to automatically implement this trait.
28/// The derive macro generates format renderers for JSON, GraphQL, HTML, and text output.
29///
30/// # Example
31///
32/// ```ignore
33/// use apollo_errors::Error;
34///
35/// #[derive(Debug, Error)]
36/// pub enum MyError {
37///     #[error("Something went wrong")]
38///     #[diagnostic(code(my_product::component::error_name))]
39///     SomethingWrong {
40///         #[extension]
41///         field: String,
42///     },
43/// }
44/// ```
45pub trait Error: std::error::Error + miette::Diagnostic {
46    /// Render this error as JSON format
47    ///
48    /// Returns a serde_json::Value with:
49    /// - `error`: The error code
50    /// - `message`: The error message
51    /// - Additional fields from `#[extension]` fields
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if any field fails to serialize to JSON
56    fn to_json(&self) -> Result<serde_json::Value, serde_json::Error>;
57
58    /// Render this error in debug format
59    ///
60    /// Returns a detailed debug representation
61    fn to_debug(&self) -> String;
62
63    /// Render this error as HTML
64    ///
65    /// Returns an HTML representation suitable for browser display
66    fn to_html(&self) -> String;
67
68    /// Render this error as GraphQL JSON format
69    ///
70    /// Returns a serde_json::Value with:
71    /// - `message`: The error message
72    /// - `extensions`: Additional structured data from `#[extension]` fields
73    /// - `code`: The diagnostic code (e.g., APOLLO_PRODUCT_COMPONENT_ERROR)
74    ///
75    /// # Errors
76    ///
77    /// Returns an error if any field fails to serialize to JSON
78    fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error>;
79
80    /// Render this error as plain text
81    ///
82    /// Returns a human-readable plain text representation
83    fn to_text(&self) -> String;
84
85    /// Render this error as JSON-RPC 2.0 error format
86    ///
87    /// Returns a serde_json::Value with:
88    /// - `code`: Integer error code (from `#[jsonrpc_code(...)]` or default -32000)
89    /// - `message`: The error message
90    /// - `data`: Object containing `diagnostic_code` and any `#[extension]` fields
91    ///
92    /// # Errors
93    ///
94    /// Returns an error if any field fails to serialize to JSON
95    fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error>;
96
97    /// Get the HTTP status code for this error
98    ///
99    /// Returns the appropriate HTTP status code (e.g., 400, 404, 500).
100    /// Defaults to 500 if not specified.
101    fn http_status(&self) -> http::StatusCode;
102
103    /// Get HTTP headers that should be returned with this error
104    ///
105    /// Returns header name-value pairs from fields marked with `#[http_header("...")]`.
106    /// For Option fields, headers are only included if the value is Some.
107    fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)>;
108}