iota_graphql_rpc/
error.rs1use async_graphql::{ErrorExtensionValues, ErrorExtensions, Pos, Response, ServerError};
6use async_graphql_axum::GraphQLResponse;
7use iota_indexer::errors::IndexerError;
8use iota_indexer_streaming::error::IndexerStreamingError;
9use iota_names::error::IotaNamesError;
10
11pub(crate) mod code {
15 pub const BAD_REQUEST: &str = "BAD_REQUEST";
16 pub const BAD_USER_INPUT: &str = "BAD_USER_INPUT";
17 pub const DATA_PRUNED: &str = "DATA_PRUNED";
18 pub const INTERNAL_SERVER_ERROR: &str = "INTERNAL_SERVER_ERROR";
19 pub const REQUEST_TIMEOUT: &str = "REQUEST_TIMEOUT";
20 pub const UNKNOWN: &str = "UNKNOWN";
21}
22
23pub(crate) fn graphql_error_response(code: &str, message: impl Into<String>) -> GraphQLResponse {
31 let error = graphql_error(code, message);
32 Response::from_errors(error.into()).into()
33}
34
35pub(crate) fn graphql_error(code: &str, message: impl Into<String>) -> ServerError {
40 let mut ext = ErrorExtensionValues::default();
41 ext.set("code", code);
42
43 ServerError {
44 message: message.into(),
45 source: None,
46 locations: vec![],
47 path: vec![],
48 extensions: Some(ext),
49 }
50}
51
52pub(crate) fn graphql_error_at_pos(
53 code: &str,
54 message: impl Into<String>,
55 pos: Pos,
56) -> ServerError {
57 let mut ext = ErrorExtensionValues::default();
58 ext.set("code", code);
59
60 ServerError {
61 message: message.into(),
62 source: None,
63 locations: vec![pos],
64 path: vec![],
65 extensions: Some(ext),
66 }
67}
68
69#[derive(Clone, Debug, thiserror::Error)]
70#[non_exhaustive]
71pub enum Error {
72 #[error("Unsupported protocol version requested. Min supported: {0}, max supported: {1}")]
73 ProtocolVersionUnsupported(u64, u64),
74 #[error("'first' and 'last' must not be used together")]
75 CursorNoFirstLast,
76 #[error("Connection's page size of {0} exceeds max of {1}")]
77 PageTooLarge(u64, u32),
78 #[error("{0}")]
80 Client(String),
81 #[error("Requested data has been pruned: {0}")]
82 DataPruned(String),
83 #[error("Internal error occurred while processing request: {0}")]
84 Internal(String),
85 #[error(transparent)]
86 IotaNames(#[from] IotaNamesError),
87 #[error("{0}")]
88 ServerInit(String),
89 #[error("Unsupported feature: {0}")]
90 UnsupportedFeature(String),
91}
92
93impl ErrorExtensions for Error {
94 fn extend(&self) -> async_graphql::Error {
95 async_graphql::Error::new(format!("{self}")).extend_with(|_err, e| match self {
96 Error::CursorNoFirstLast
97 | Error::PageTooLarge(_, _)
98 | Error::ProtocolVersionUnsupported(_, _)
99 | Error::Client(_) => {
100 e.set("code", code::BAD_USER_INPUT);
101 }
102 Error::DataPruned(_) => {
103 e.set("code", code::DATA_PRUNED);
104 }
105 Error::Internal(_) => {
106 e.set("code", code::INTERNAL_SERVER_ERROR);
107 }
108 Error::IotaNames(_) => {
109 e.set("code", code::BAD_REQUEST);
110 }
111 Error::ServerInit(_) => {
112 e.set("code", code::UNKNOWN);
113 }
114 Error::UnsupportedFeature(_) => {
115 e.set("code", code::BAD_REQUEST);
116 }
117 })
118 }
119}
120
121impl From<IndexerError> for Error {
122 fn from(e: IndexerError) -> Self {
123 match e {
124 IndexerError::DataPruned(msg) => Error::DataPruned(msg),
125 _ => Error::Internal(e.to_string()),
126 }
127 }
128}
129
130impl From<IndexerStreamingError> for Error {
131 fn from(e: IndexerStreamingError) -> Self {
132 Error::Internal(e.to_string())
133 }
134}