grafbase_local_server/
errors.rs1use axum::http::StatusCode;
2use axum::response::IntoResponse;
3use axum::response::Response;
4use axum::Json;
5use hyper::Error as HyperError;
6use notify::Error as NotifyError;
7use serde_json::json;
8use sqlx::Error as SqlxError;
9use std::io::Error as IoError;
10use std::path::PathBuf;
11use thiserror::Error;
12use tokio::task::JoinError;
13
14use crate::custom_resolvers::JavaScriptPackageManager;
15
16#[derive(Error, Debug)]
17pub enum ServerError {
18 #[error("could not create path '{0}' for the embedded server files")]
20 CreateDir(PathBuf),
21
22 #[error("could not write an embedded server file: {0}")]
24 WriteFile(String),
25
26 #[error("could not read the previously extracted embedded file versions")]
28 ReadVersion,
29
30 #[error("could not connect to the sqlite database: {0}")]
32 ConnectToDatabase(SqlxError),
33
34 #[error("could not create an sqlite database file: {0}")]
36 CreateDatabase(SqlxError),
37
38 #[error("could not query the sqlite database: {0}")]
40 QueryDatabase(SqlxError),
41
42 #[error("encountered an unknown sqlite error: {0}")]
44 UnknownSqliteError(SqlxError),
45
46 #[error("the bridge api encountered an error: {0}")]
48 BridgeApi(#[from] HyperError),
49
50 #[error("miniflare encountered an error: {0}")]
52 MiniflareCommandError(IoError),
53
54 #[error("miniflare encountered an error\ncause:\n{0}")]
56 MiniflareError(String),
57
58 #[error(transparent)]
60 SchemaParserError(IoError),
61
62 #[error(transparent)]
64 SchemaParserResultRead(IoError),
65
66 #[error("schema parser result is malformed JSON:\n{0}")]
68 SchemaParserResultJson(serde_json::Error),
69
70 #[error(transparent)]
72 SchemaRegistryWrite(IoError),
73
74 #[error("could not create a temporary file for the parser result: {0}")]
76 CreateTemporaryFile(IoError),
77
78 #[error("could not create an output artifact file during a resolver build")]
80 CreateResolverArtifactFile(IoError),
81
82 #[error("could not extract the resolver wrapper worker contents")]
84 ExtractResolverWrapperWorkerContents(String),
85
86 #[error("could not parse grafbase/schema.graphql\n{0}")]
88 ParseSchema(String),
89
90 #[error("could not find a resolver referenced in the schema under the path {0}.{{js,ts}}")]
91 ResolverDoesNotExist(PathBuf),
92
93 #[error("{0} encountered an error: {1}")]
95 ResolverPackageManagerCommandError(JavaScriptPackageManager, IoError),
96
97 #[error("{0} failed with output:\n{1}")]
99 ResolverPackageManagerError(JavaScriptPackageManager, String),
100
101 #[error("resolver {0} failed to build:\n{1}")]
103 ResolverBuild(String, String),
104
105 #[error("non utf-8 path used for project")]
107 ProjectPath,
108
109 #[error("$HOME/.grafbase is a non utf8 path")]
111 CachePath,
112
113 #[error("could not create a project cache directory")]
115 CreateCacheDir,
116
117 #[error("could not create a project database directory\ncaused by: {0}")]
119 CreateDatabaseDir(IoError),
120
121 #[error("could not read the project database directory\ncaused by: {0}")]
123 ReadDatabaseDir(IoError),
124
125 #[error("could not find an available port for the bridge server")]
127 AvailablePort,
128
129 #[error(transparent)]
131 SpawnedTaskPanic(#[from] JoinError),
132
133 #[error("Node.js does not seem to be installed")]
135 NodeInPath,
136
137 #[error("Node.js version {0} is unsupported")]
139 OutdatedNode(String, String),
140
141 #[error("Could not retrive the installed version of Node.js")]
143 CheckNodeVersion,
144
145 #[error("A file watcher encountered an error\ncaused by: {0}")]
147 FileWatcher(#[from] NotifyError),
148}
149
150impl From<SqlxError> for ServerError {
151 fn from(error: SqlxError) -> Self {
152 match error {
153 SqlxError::RowNotFound
154 | SqlxError::TypeNotFound { .. }
155 | SqlxError::ColumnNotFound(_)
156 | SqlxError::ColumnDecode { .. }
157 | SqlxError::ColumnIndexOutOfBounds { .. }
158 | SqlxError::Io(_)
159 | SqlxError::Decode(_)
160 | SqlxError::Database(_) => Self::QueryDatabase(error),
161
162 SqlxError::Configuration(_)
163 | SqlxError::Tls(_)
164 | SqlxError::PoolTimedOut
165 | SqlxError::Protocol(_)
166 | SqlxError::PoolClosed
167 | SqlxError::WorkerCrashed => Self::ConnectToDatabase(error),
168
169 SqlxError::Migrate(_) => Self::CreateDatabase(error),
170
171 _ => Self::UnknownSqliteError(error),
172 }
173 }
174}
175
176impl IntoResponse for ServerError {
177 fn into_response(self) -> Response {
178 let body = Json(json!({
179 "error": self.to_string(),
180 }));
181
182 (StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
183 }
184}