apollo_federation/connectors/runtime/
errors.rs1use serde::Serialize;
2use serde_json_bytes::ByteString;
3use serde_json_bytes::Map;
4use serde_json_bytes::Value;
5
6use crate::connectors::Connector;
7use crate::connectors::runtime::key::ResponseKey;
8
9#[derive(Clone, Debug, Serialize)]
10pub struct RuntimeError {
11 pub message: String,
12 code: Option<String>,
13 pub coordinate: Option<String>,
14 pub subgraph_name: Option<String>,
15 pub path: String,
16 pub extensions: Map<ByteString, Value>,
17}
18
19impl RuntimeError {
20 pub fn new(message: impl Into<String>, response_key: &ResponseKey) -> Self {
21 Self {
22 message: message.into(),
23 code: None,
24 coordinate: None,
25 subgraph_name: None,
26 path: response_key.path_string(),
27 extensions: Default::default(),
28 }
29 }
30
31 pub fn extensions(&self) -> Map<ByteString, Value> {
32 let mut extensions = Map::default();
33 extensions
34 .entry("code")
35 .or_insert_with(|| self.code().into());
36 if let Some(subgraph_name) = &self.subgraph_name {
37 extensions
38 .entry("service")
39 .or_insert_with(|| Value::String(subgraph_name.clone().into()));
40 };
41
42 if let Some(coordinate) = &self.coordinate {
43 extensions.entry("connector").or_insert_with(|| {
44 Value::Object(Map::from_iter([(
45 "coordinate".into(),
46 Value::String(coordinate.to_string().into()),
47 )]))
48 });
49 }
50
51 extensions.extend(self.extensions.clone());
52 extensions
53 }
54
55 pub fn extension<K, V>(mut self, key: K, value: V) -> Self
56 where
57 K: Into<ByteString>,
58 V: Into<Value>,
59 {
60 self.extensions.insert(key.into(), value.into());
61 self
62 }
63
64 pub fn with_code(mut self, code: impl Into<String>) -> Self {
65 self.code = Some(code.into());
66 self
67 }
68
69 pub fn code(&self) -> &str {
70 self.code.as_deref().unwrap_or("CONNECTORS_FETCH")
71 }
72}
73
74#[derive(Debug, Clone, thiserror::Error)]
77pub enum Error {
78 #[error("Request limit exceeded")]
79 RequestLimitExceeded,
80
81 #[error("Rate limit exceeded")]
82 RateLimited,
83
84 #[error("Gateway timeout")]
85 GatewayTimeout,
86
87 #[error("Connector error: {0}")]
88 TransportFailure(String),
89}
90
91impl Error {
92 pub fn to_runtime_error(
93 &self,
94 connector: &Connector,
95 response_key: &ResponseKey,
96 ) -> RuntimeError {
97 RuntimeError {
98 message: self.to_string(),
99 code: Some(self.code().to_string()),
100 coordinate: Some(connector.id.coordinate()),
101 subgraph_name: Some(connector.id.subgraph_name.clone()),
102 path: response_key.path_string(),
103 extensions: Default::default(),
104 }
105 }
106
107 pub fn code(&self) -> &'static str {
108 match self {
109 Self::RequestLimitExceeded => "REQUEST_LIMIT_EXCEEDED",
110 Self::RateLimited => "REQUEST_RATE_LIMITED",
111 Self::GatewayTimeout => "GATEWAY_TIMEOUT",
112 Self::TransportFailure(_) => "HTTP_CLIENT_ERROR",
113 }
114 }
115}