1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
//! This module provides error handling for WarpGrapher. use serde_yaml; use std::error; use std::fmt::{Display, Formatter, Result}; use std::sync::mpsc::RecvError; /// Categories of Warpgrapher errors. #[derive(Debug)] pub enum ErrorKind { /// Returned when the server attempts to listen on an address/port /// combination that is already bound on the system. AddrInUse(std::io::Error), /// Returned when the server attempts to listen on an address not /// assigned to any of the system's interfaces. AddrNotAvailable(std::io::Error), /// Returned when `WarpgrapherClient` receives an HTTP response which /// contains a body that is not valid JSON. All GraphQL responses /// including errors are expected to be in the form of valid JSON. ClientReceivedInvalidJson, /// Returned when `WarpgrapherClient` is unable to submit a request to /// the server (network error or server error). ClientRequestFailed(String), /// Returned when `WarpgrapherClient` receives a valid JSON response /// that does not contain the expected 'data' or 'errors' objects. ClientRequestUnexpectedPayload(serde_json::Value), /// Returned when a custom endpoint defines an inline custom input type /// with a name that conflicts with a GraphQL scalar ConfigEndpointInputTypeScalarNameError(String, String), /// Returned when a custom endpoint defines an inline custom output type /// with a name that conflicts with a GraphQL scalar ConfigEndpointOutputTypeScalarNameError(String, String), /// Returned when a warpgrapher type is defined with a name that conflicts with /// a GraphQL scalar ConfigTypeScalarNameError(String, String), /// Returned when a `WarpgrapherConfig` struct attempts to be initialized /// from a config file that cannot be found on disk. ConfigNotFound(std::io::Error), /// Returned when a `WarpgrapherConfig` fails to deserialize because the /// provided data does not match the expected config spec ConfigDeserializationError(serde_yaml::Error), /// Returned when attempting to compose configs with different versions ConfigVersionMismatchError(String, i32), /// Returned when two warpgrapher types are defined with the same name ConfigTypeDuplicateError(String, String), /// Returned when two warpgrapher endpoints are defined with the same name ConfigEndpointDuplicateError(String, String), /// Returned when a warpgrapher endpoint defines for an input or output a /// type that does not exist ConfigEndpointMissingTypeError(String, String), /// Returned when `WarpgrapherServer` fails to build a pool for the cypher /// connection manager. CouldNotBuildCypherPool(r2d2::Error), /// Returned when the internal resolver logic cannot infer the correct warpgrapher type /// that corresponds to data queried from the database. /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. CouldNotInferType, /// Returned when an environment variable cannot be found EnvironmentVariableNotFound(String), /// Returned when there is a mismatch in the expected internal representation of a /// warpgrapher type /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. InputTypeMismatch(String), /// Returned when trying to perform on operation on a type that cannot support it. /// For example, this would be returned when trying to load a relationship from /// an input, as input types don't have relationships. This is a critical internal /// error. If you see it, please report it to the warpgrapher team. InvalidType(String), /// Returned when received GraphQL input contains an invalid property /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. InvalidProperty(String), /// Returned when there is a mismatch in the expected internal representation of a /// warpgrapher type /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. InvalidPropertyType(String), /// Returned during config validation if the config defines a Type or Rel property with the name 'ID'. /// ID is a reserved prop used by the Warpgrapher internals. InvalidPropNameID(String), /// Returned when attempts to serialize/deserialize a struct to/from JSON fails JsonError(serde_json::error::Error), /// Returned when a resolver's input is missing an expected argument. Given /// GraphQL's type system /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. MissingArgument(String), /// Returned when warpgrapher missing a property expected for that node or rel type. /// This could occur if a node or relationship is created with a direct cypher query /// in a custom resolver or external to Warpgrapher altogether, without creating an /// 'id' property with a UUID. This could also occur if a schema change makes a /// previously optional and nullable property mandatory and non-nullable. MissingProperty(String, Option<String>), /// Returned when the cursor points outside of the bounds of the data returned /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. MissingResultSet, /// Returned when there is a mismatch between the data returned from the database /// and what the internal representation of a warpgrapher type expects MissingResultElement(String), /// Returned at start time when warpgrapher is dynamically generating a GraphQL schema /// from the config but there is a mismatch in the schema. /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. MissingSchemaElement(String), /// Returned when a field (prop or rel) of a node has been determined to be a DynamicScalar /// type and will attempt to execute a custom resolver for that field. This error is /// returned if the resolver is not defined for that DynamicScalar type field. /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. FieldMissingResolverError(String, String), /// Returned when there is a failure executing a neo4j query and the expected results /// from the database are not returned. GraphQueryError(rusted_cypher::error::GraphError), /// Returned when the output of a GraphQL execution is not a valid JSON. /// Note: This error should never be thrown. This is a critical error. If you see it, /// please report it to the warpgrapher team. GraphQLOutputError(String), /// Returned when a resolver attempt to infer relationships between queried data via /// a regex match fails RegexError, /// Returned when a custom endpoint is defined or a resolver is /// defined for a field, but the corresponding resolver is not provided. ResolverNotFound(String, String), /// Returned when a `WarpgrapherServer` tries to shutdown but the server is not /// running. ServerNotRunning, /// Returned when an error is encountered while trying to shutdown a `WarpgrapherServer` /// that is supposed to be running. ServerShutdownFailed, /// Returned when a `WarpgrapherServer` that is already running tries to start. ServerAlreadyRunning, /// Returned when a `WarpgrapherServer` fails to start. ServerStartupFailed(RecvError), /// Returned when a custom input validator is defined, but the corresponding /// validator is not provided. ValidatorNotFound(String, String), /// This error is returned by a custom input validator when the validation fails. /// This error is converted into a FieldError and returned to the client. ValidationError(String), } /// Error type for Warpgrapher operations. /// /// Many errors originate in underlying libraries, but the /// [`ErrorKind`] wraps these as necessary into /// Warpgrapher errors. /// /// [`ErrorKind`]: ./enum.ErrorKind.html #[derive(Debug)] pub struct Error { pub kind: ErrorKind, source: Option<Box<dyn error::Error + Send + Sync>>, } impl Error { /// Creates a new Warpgrapher error from an [`ErrorKind`] and, /// optionally, an arbitrary source error. /// /// [`ErrorKind`]: ./enum.ErrorKind.html /// /// # Examples /// /// ```rust /// use warpgrapher::{Error, ErrorKind}; /// /// let e1 = Error::new(ErrorKind::ServerAlreadyRunning, None); /// /// let s = std::io::Error::new(std::io::ErrorKind::Other, "Oh no!"); /// let e2 = Error::new(ErrorKind::ServerShutdownFailed, Some(Box::new(s))); /// ``` pub fn new(kind: ErrorKind, source: Option<Box<dyn error::Error + Send + Sync>>) -> Error { Error { kind, source } } } impl Display for Error { fn fmt(&self, fmt: &mut Formatter) -> Result { write!( fmt, "ErrorKind: {:#?}, source: {:#?}", self.kind, self.source ) } } impl error::Error for Error {} #[cfg(test)] mod tests { use super::{Error, ErrorKind}; /// Passes if a new error with no wrapped source error is created #[test] fn new_error() { let e = Error::new(ErrorKind::ServerAlreadyRunning, None); assert!(std::error::Error::source(&e).is_none()); } /// Passes if an error prints a display string correctly #[test] fn display_fmt() { let s = std::io::Error::new(std::io::ErrorKind::Other, "oh no!"); let e = Error::new(ErrorKind::ServerShutdownFailed, Some(Box::new(s))); assert!(&format!("{}", e).starts_with("ErrorKind: ServerShutdownFailed, source: Some")); } }