Skip to main content

mongo_graphql/
error.rs

1use async_graphql::ErrorExtensions;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5#[non_exhaustive]
6pub enum GraphQLError {
7    #[error("Config error: {0}")]
8    Config(String),
9
10    #[error("Schema parse error at {location}: {message}")]
11    SchemaParse { message: String, location: String },
12
13    #[error("Schema build error: {0}")]
14    SchemaBuild(String),
15
16    #[error("Database error: {0}")]
17    Database(String),
18
19    #[error("Not found: {message}")]
20    NotFound { message: String },
21
22    #[error("Duplicate key: {message}")]
23    DuplicateKey { message: String },
24
25    #[error("Pagination error: {0}")]
26    Pagination(String),
27
28    #[error("Unauthorized: {0}")]
29    Unauthorized(String),
30
31    #[error("Forbidden: {0}")]
32    Forbidden(String),
33
34    /// The message is NEVER exposed to the client.
35    #[error("Internal error: {0}")]
36    Internal(String),
37}
38
39impl GraphQLError {
40    /// Convert this error into an `async_graphql::Error` with structured extensions.
41    pub fn into_graphql_error(self) -> async_graphql::Error {
42        let message = self.to_string();
43        match &self {
44            GraphQLError::NotFound { .. } => {
45                async_graphql::Error::new(message).extend_with(|_, extensions| {
46                    extensions.set("code", "NOT_FOUND");
47                })
48            }
49            GraphQLError::Unauthorized(_) => {
50                async_graphql::Error::new(message).extend_with(|_, extensions| {
51                    extensions.set("code", "UNAUTHORIZED");
52                })
53            }
54            GraphQLError::Forbidden(_) => {
55                async_graphql::Error::new(message).extend_with(|_, extensions| {
56                    extensions.set("code", "FORBIDDEN");
57                })
58            }
59            GraphQLError::DuplicateKey { .. } => {
60                async_graphql::Error::new(message).extend_with(|_, extensions| {
61                    extensions.set("code", "DUPLICATE_KEY");
62                })
63            }
64            GraphQLError::Pagination(_) => {
65                async_graphql::Error::new(message).extend_with(|_, extensions| {
66                    extensions.set("code", "INVALID_CURSOR");
67                })
68            }
69            GraphQLError::Database(_)
70            | GraphQLError::Internal(_)
71            | GraphQLError::SchemaParse { .. }
72            | GraphQLError::SchemaBuild(_)
73            | GraphQLError::Config(_) => {
74                async_graphql::Error::new("Internal server error")
75            }
76        }
77    }
78}
79
80impl From<async_graphql::Error> for GraphQLError {
81    fn from(e: async_graphql::Error) -> Self {
82        GraphQLError::Internal(e.message)
83    }
84}
85
86impl From<mongodb::error::Error> for GraphQLError {
87    fn from(e: mongodb::error::Error) -> Self {
88        GraphQLError::Database(format!("MongoDB error: {}", e))
89    }
90}