grafbase_local_backend/api/
errors.rs

1use cynic::http::CynicReqwestError;
2use std::{io, path::PathBuf};
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum ApiError {
7    /// returned if the login server could not be started
8    #[error("could not start the login server")]
9    StartLoginServer,
10
11    /// returned if the user is not logged in when attempting to use a command requiring auth
12    #[error("could not proceed as you are not logged in")]
13    NotLoggedIn,
14
15    /// returned if ~/.grafbase/credentials.json could not be deleted
16    #[error("could not delete '~/.grafbase/credentials.json'\ncaused by: {0}")]
17    DeleteCredentialsFile(io::Error),
18
19    /// returned if ~/.grafbase/project.json could not be deleted
20    #[error("could not delete '~/.grafbase/project.json'\ncaused by: {0}")]
21    DeleteProjectMetadataFile(io::Error),
22
23    /// returned if ~/.grafbase/credentials.json could not be read
24    #[error("could not read '~/.grafbase/credentials.json'\ncaused by: {0}")]
25    ReadCredentialsFile(io::Error),
26
27    /// returned if .grafbase/project.json could not be read
28    #[error("could not read '.grafbase/project.json'\ncaused by: {0}")]
29    ReadProjectMetadataFile(io::Error),
30
31    /// returned if ~/.grafbase could not be read
32    #[error("could not read '~/.grafbase'\ncaused by: {0}")]
33    ReadUserDotGrafbaseFolder(io::Error),
34
35    /// returned if .grafbase could not be read
36    #[error("could not read '.grafbase'\ncaused by: {0}")]
37    ReadProjectDotGrafbaseFolder(io::Error),
38
39    /// returned if an operation failed due to the project not being linked
40    #[error("could not complete the action as this project has not been linked")]
41    UnlinkedProject,
42
43    /// returned if the contents of the credential file are corrupt
44    #[error("could not complete the action as your credential file is corrupt")]
45    CorruptCredentialsFile,
46
47    /// returned if the provided access token is corrupt
48    #[error("could not complete the action as your access token is corrupt")]
49    CorruptAccessToken,
50
51    /// returned if the contents of the project metadata file are corrupt
52    #[error("could not complete the action as your project metadata file are corrupt")]
53    CorruptProjectMetadataFile,
54
55    /// returned if an operation failed due to a token being unauthorized or the user previously being deleted
56    #[error("unauthorized or deleted user")]
57    UnauthorizedOrDeletedUser,
58
59    /// returned if a token does not have access to a user's personal account
60    #[error("incorrectly scoped token")]
61    IncorrectlyScopedToken,
62
63    /// returned if a project schema could not be read
64    #[error("could not read the project graphql schema")]
65    ReadSchema,
66
67    /// returned if the project metadata file could not be written
68    #[error("could not write the project metadata file\ncaused by: {0}")]
69    WriteProjectMetadataFile(io::Error),
70
71    /// returned if a cynic request could not be completed
72    #[error("could not complete a request")]
73    RequestError,
74
75    /// returned if a cynic request could not be completed (due to connection issues)
76    #[error("could not complete a request")]
77    ConnectionError,
78
79    /// returned if a project being created has already been created
80    #[error("could not proceed as this local project has already been linked to a remote project")]
81    ProjectAlreadyLinked,
82
83    /// returned if the path of ~/.grafbase could not be found
84    #[error("could not find the current user home folder")]
85    FindUserDotGrafbaseFolder,
86
87    /// returned if ~/.grafbase could not be created
88    #[error("could not create '~/.grafbase'\ncaused by: {0}")]
89    CreateUserDotGrafbaseFolder(io::Error),
90
91    /// returned if .grafbase could not be created
92    #[error("could not create '.grafbase'\ncaused by: {0}")]
93    CreateProjectDotGrafbaseFolder(io::Error),
94
95    /// returned if an available port could not be find
96    #[error("could not find an available port")]
97    FindAvailablePort,
98
99    /// returned if a the request to upload the archive fails
100    #[error("could not complete the request to upload the deployment archive")]
101    UploadError,
102
103    /// returned if the upload archive metadata could not be read
104    #[error("could not read the upload archive metadata\ncaused by: {0}")]
105    ReadArchiveMetadata(io::Error),
106
107    /// returned if the upload archive could not be read
108    #[error("could not read the upload archive\ncaused by: {0}")]
109    ReadArchive(io::Error),
110
111    /// returned if a file or directory could not be appended to the upload archive
112    #[error("could not append a file or directory to the upload archive\ncaused by: {0}")]
113    AppendToArchive(io::Error),
114
115    /// returned if a temporary file for the upload archive could not be created
116    #[error("could not create a temporary file\ncaused by: {0}")]
117    CreateTempFile(io::Error),
118
119    /// wraps a [`CreateError`]
120    #[error(transparent)]
121    CreateError(#[from] CreateError),
122
123    /// wraps a [`DeployError`]
124    #[error(transparent)]
125    DeployError(#[from] DeployError),
126}
127
128#[derive(Error, Debug)]
129pub enum CreateError {
130    /// returned if the given slug for a new project is already in use
131    #[error("could not create a new project as the provided slug is already in use")]
132    SlugAlreadyExists,
133
134    /// returned if the given slug for a new project is invalid
135    #[error("could not create a new project as the provided slug is invalid")]
136    SlugInvalid,
137
138    /// returned if the given slug for a new project was too long
139    #[error("could not create a new project as the provided slug is longer than {max_length} characters")]
140    SlugTooLong { max_length: i32 },
141
142    /// returned if a given account ID does not exist
143    #[error("could not create a new project as the specified account ID does not exist")]
144    AccountDoesNotExist,
145
146    /// returned if the user has reached the current plan limit
147    #[error("could not create a new project as the current plan limit of {max} projects has been reached")]
148    CurrentPlanLimitReached { max: i32 },
149
150    /// returned if duplicate database regions were selected
151    #[error("could not create a new project as duplicate database regions were selected")]
152    DuplicateDatabaseRegions { duplicates: Vec<String> },
153
154    /// returned if no database regions are selected
155    #[error("could not create a new project as no database regions were selected")]
156    EmptyDatabaseRegions,
157
158    /// returned if invalid database regions are used
159    #[error("could not create a new project as invalid regions were selected")]
160    InvalidDatabaseRegions { invalid: Vec<String> },
161
162    /// returned if an unknown error occurs
163    #[error("could not create a new project, encountered an unknown error")]
164    Unknown,
165}
166
167#[derive(Error, Debug)]
168pub enum DeployError {
169    /// returned if the linked project does not exist
170    #[error("could not deploy as the linked project does not exist")]
171    ProjectDoesNotExist,
172
173    /// returned if the uploaded archive size is over the allowed limit
174    #[error("could not deploy as the created archive size is above the allowed limit of {limit} bytes")]
175    ArchiveFileSizeLimitExceeded { limit: i32 },
176
177    /// returned if the daily deployment count is passed
178    #[error("could not deploy as you have reached the allowed daily deployemnt amount of {limit}")]
179    DailyDeploymentCountLimitExceeded { limit: i32 },
180
181    /// returned if an unknown error occurs
182    #[error("could not deploy, encountered an unknown error")]
183    Unknown,
184}
185
186#[derive(Error, Debug)]
187pub enum LoginApiError {
188    #[error("could not write '{0}'")]
189    WriteCredentialFile(PathBuf),
190}
191
192impl From<CynicReqwestError> for ApiError {
193    fn from(error: CynicReqwestError) -> Self {
194        match error {
195            CynicReqwestError::ReqwestError(error) if error.is_connect() => ApiError::ConnectionError,
196            CynicReqwestError::ReqwestError(_) | CynicReqwestError::ErrorResponse(_, _) => ApiError::RequestError,
197        }
198    }
199}