sui_graphql_client/
error.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::num::ParseIntError;
5use std::num::TryFromIntError;
6
7use cynic::GraphQlError;
8
9use sui_types::AddressParseError;
10use sui_types::DigestParseError;
11use sui_types::TypeParseError;
12
13type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
14
15pub type Result<T, E = Error> = std::result::Result<T, E>;
16
17/// General error type for the client. It is used to wrap all the possible errors that can occur.
18#[derive(Debug)]
19pub struct Error {
20    inner: Box<InnerError>,
21}
22
23/// Error type for the client. It is split into multiple fields to allow for more granular error
24/// handling. The `source` field is used to store the original error.
25#[derive(Debug)]
26struct InnerError {
27    /// Error kind.
28    kind: Kind,
29    /// Errors returned by the GraphQL server.
30    query_errors: Option<Vec<GraphQlError>>,
31    /// The original error.
32    source: Option<BoxError>,
33}
34
35#[derive(Debug)]
36#[non_exhaustive]
37pub enum Kind {
38    Deserialization,
39    Parse,
40    Query,
41    Other,
42}
43
44impl std::error::Error for Error {
45    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
46        self.inner.source.as_deref().map(|e| e as _)
47    }
48}
49
50impl Error {
51    // Public accessors
52
53    /// Returns the kind of error.
54    pub fn kind(&self) -> &Kind {
55        &self.inner.kind
56    }
57
58    /// Original GraphQL query errors.
59    pub fn graphql_errors(&self) -> Option<&[GraphQlError]> {
60        self.inner.query_errors.as_deref()
61    }
62
63    // Private constructors
64
65    /// Convert the given error into a generic error.
66    pub fn from_error<E: Into<BoxError>>(kind: Kind, error: E) -> Self {
67        Self {
68            inner: Box::new(InnerError {
69                kind,
70                source: Some(error.into()),
71                query_errors: None,
72            }),
73        }
74    }
75
76    /// Special constructor for queries that expect to return data but it's none.
77    pub fn empty_response_error() -> Self {
78        Self {
79            inner: Box::new(InnerError {
80                kind: Kind::Query,
81                source: Some("Expected a non-empty response data from query".into()),
82                query_errors: None,
83            }),
84        }
85    }
86
87    /// Create a Query kind of error with the original graphql errors.
88    pub fn graphql_error(errors: Vec<GraphQlError>) -> Self {
89        Self {
90            inner: Box::new(InnerError {
91                kind: Kind::Query,
92                source: None,
93                query_errors: Some(errors),
94            }),
95        }
96    }
97}
98
99impl std::fmt::Display for Kind {
100    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
101        match self {
102            Kind::Deserialization => write!(f, "Deserialization error:"),
103            Kind::Parse => write!(f, "Parse error:"),
104            Kind::Query => write!(f, "Query error:"),
105            Kind::Other => write!(f, "Error:"),
106        }
107    }
108}
109
110impl std::fmt::Display for Error {
111    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112        write!(f, "{}", self.inner.kind)?;
113
114        if let Some(source) = &self.inner.source {
115            writeln!(f, " {}", source)?;
116        }
117        Ok(())
118    }
119}
120
121impl From<bcs::Error> for Error {
122    fn from(error: bcs::Error) -> Self {
123        Self::from_error(Kind::Deserialization, error)
124    }
125}
126
127impl From<reqwest::Error> for Error {
128    fn from(error: reqwest::Error) -> Self {
129        Self::from_error(Kind::Other, error)
130    }
131}
132
133impl From<url::ParseError> for Error {
134    fn from(error: url::ParseError) -> Self {
135        Self::from_error(Kind::Parse, error)
136    }
137}
138
139impl From<ParseIntError> for Error {
140    fn from(error: ParseIntError) -> Self {
141        Self::from_error(Kind::Parse, error)
142    }
143}
144
145impl From<AddressParseError> for Error {
146    fn from(error: AddressParseError) -> Self {
147        Self::from_error(Kind::Parse, error)
148    }
149}
150
151impl From<base64ct::Error> for Error {
152    fn from(error: base64ct::Error) -> Self {
153        Self::from_error(Kind::Parse, error)
154    }
155}
156
157impl From<chrono::ParseError> for Error {
158    fn from(error: chrono::ParseError) -> Self {
159        Self::from_error(Kind::Parse, error)
160    }
161}
162
163impl From<DigestParseError> for Error {
164    fn from(error: DigestParseError) -> Self {
165        Self::from_error(Kind::Parse, error)
166    }
167}
168
169impl From<TryFromIntError> for Error {
170    fn from(error: TryFromIntError) -> Self {
171        Self::from_error(Kind::Parse, error)
172    }
173}
174
175impl From<TypeParseError> for Error {
176    fn from(error: TypeParseError) -> Self {
177        Self::from_error(Kind::Parse, error)
178    }
179}