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}