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