Skip to main content

apollo_errors/
error.rs

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