firebase_rs_sdk/data_connect/
error.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::fmt::{self, Display, Formatter};
4
5/// Result alias returned by Data Connect APIs.
6pub type DataConnectResult<T> = Result<T, DataConnectError>;
7
8/// Enumerates the canonical error codes surfaced by the Data Connect module.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
10pub enum DataConnectErrorCode {
11    /// The client supplied an invalid argument (missing connector config, etc.).
12    InvalidArgument,
13    /// The client attempted to reuse an instance in an incompatible configuration.
14    AlreadyInitialized,
15    /// The service has not been initialized yet.
16    NotInitialized,
17    /// The current platform does not support the requested feature.
18    NotSupported,
19    /// The backend rejected the request because authentication was missing/invalid.
20    Unauthorized,
21    /// The backend returned a GraphQL `errors` payload.
22    PartialError,
23    /// Any other internal client failure.
24    Internal,
25    /// Unknown errors reported by the backend or transport layer.
26    Other,
27}
28
29impl DataConnectErrorCode {
30    /// Returns the string form exposed to callers.
31    pub fn as_str(&self) -> &'static str {
32        match self {
33            DataConnectErrorCode::InvalidArgument => "data-connect/invalid-argument",
34            DataConnectErrorCode::AlreadyInitialized => "data-connect/already-initialized",
35            DataConnectErrorCode::NotInitialized => "data-connect/not-initialized",
36            DataConnectErrorCode::NotSupported => "data-connect/not-supported",
37            DataConnectErrorCode::Unauthorized => "data-connect/unauthorized",
38            DataConnectErrorCode::PartialError => "data-connect/partial-error",
39            DataConnectErrorCode::Internal => "data-connect/internal",
40            DataConnectErrorCode::Other => "data-connect/other",
41        }
42    }
43}
44
45/// Rich failure type returned by Data Connect operations.
46#[derive(Clone, Debug, Serialize, Deserialize)]
47pub struct DataConnectError {
48    code: DataConnectErrorCode,
49    message: String,
50    operation_failure: Option<DataConnectOperationFailureResponse>,
51}
52
53impl DataConnectError {
54    /// Creates a new error with the specified code and message.
55    pub fn new(code: DataConnectErrorCode, message: impl Into<String>) -> Self {
56        Self {
57            code,
58            message: message.into(),
59            operation_failure: None,
60        }
61    }
62
63    /// Creates an error that captures the backend-provided GraphQL payload.
64    pub fn with_operation_failure(
65        message: impl Into<String>,
66        response: DataConnectOperationFailureResponse,
67    ) -> Self {
68        Self {
69            code: DataConnectErrorCode::PartialError,
70            message: message.into(),
71            operation_failure: Some(response),
72        }
73    }
74
75    /// Returns the canonical error code string.
76    pub fn code_str(&self) -> &'static str {
77        self.code.as_str()
78    }
79
80    /// Returns the structured error code.
81    pub fn code(&self) -> DataConnectErrorCode {
82        self.code
83    }
84
85    /// Returns the human readable description.
86    pub fn message(&self) -> &str {
87        &self.message
88    }
89
90    /// Returns the backend failure payload when the code is `PartialError`.
91    pub fn operation_failure(&self) -> Option<&DataConnectOperationFailureResponse> {
92        self.operation_failure.as_ref()
93    }
94}
95
96impl Display for DataConnectError {
97    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
98        write!(f, "{} ({})", self.message, self.code.as_str())
99    }
100}
101
102impl std::error::Error for DataConnectError {}
103
104/// GraphQL error payload mirrored from the JS SDK.
105#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
106pub struct DataConnectOperationFailureResponse {
107    /// Partial data returned by the backend, if any.
108    pub data: Option<Value>,
109    /// The list of GraphQL errors reported for the operation.
110    pub errors: Vec<DataConnectOperationFailureResponseErrorInfo>,
111}
112
113/// Individual error entry returned by the GraphQL endpoint.
114#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
115pub struct DataConnectOperationFailureResponseErrorInfo {
116    /// Error summary message.
117    pub message: String,
118    /// Path into the GraphQL response that triggered the failure.
119    pub path: Vec<DataConnectErrorPathSegment>,
120}
121
122/// A single entry in the `path` array from a GraphQL error response.
123#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
124#[serde(untagged)]
125pub enum DataConnectErrorPathSegment {
126    Field(String),
127    Index(i64),
128}
129
130impl Display for DataConnectErrorPathSegment {
131    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
132        match self {
133            DataConnectErrorPathSegment::Field(field) => write!(f, "{}", field),
134            DataConnectErrorPathSegment::Index(idx) => write!(f, "{}", idx),
135        }
136    }
137}
138
139/// Helper for constructing an invalid argument error.
140pub fn invalid_argument(message: impl Into<String>) -> DataConnectError {
141    DataConnectError::new(DataConnectErrorCode::InvalidArgument, message)
142}
143
144/// Helper for constructing an unauthorized error.
145pub fn unauthorized(message: impl Into<String>) -> DataConnectError {
146    DataConnectError::new(DataConnectErrorCode::Unauthorized, message)
147}
148
149/// Helper for constructing an internal error.
150pub fn internal_error(message: impl Into<String>) -> DataConnectError {
151    DataConnectError::new(DataConnectErrorCode::Internal, message)
152}
153
154/// Helper for surfacing partial/GraphQL errors from the backend.
155pub fn operation_error(
156    message: impl Into<String>,
157    response: DataConnectOperationFailureResponse,
158) -> DataConnectError {
159    DataConnectError::with_operation_failure(message, response)
160}