From 35561c48c0052aab336bab643dfe4d892f429db1 Mon Sep 17 00:00:00 2001 From: Anders Eie <1128648+strykejern@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:02:32 +0200 Subject: [PATCH] Add better error reporting from storage --- src/lib.rs | 2 ++ src/storage/mod.rs | 50 +++++++++++++++++++++++++++++++++++++++++++ src/storage/object.rs | 37 ++++++++++++++++++-------------- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cf89740..4302215 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,6 +142,8 @@ pub enum SupabaseError { /// Missing authentication information. Maybe you are not logged in? #[error("Missing authentication information. Maybe you are not logged in?")] MissingAuthenticationInformation, + #[error("Error from storage: {0}")] + Storage(#[from] storage::Error), #[error("Request failed")] Reqwest(#[from] reqwest::Error), #[error("Error from auth layer: {0}")] diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 1b73316..65ad14a 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -39,6 +39,21 @@ pub struct Storage { url_base: String, } +/// errorSchema as defined under schemas at [the api documentation](https://supabase.github.io/storage/) +#[derive(Debug, Clone, PartialEq, serde::Deserialize, thiserror::Error)] +pub struct Error { + #[serde(rename = "statusCode")] + pub status_code: String, + pub error: String, + pub message: String, +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + impl Storage { /// Object end-points pub fn object(self) -> object::Object { @@ -62,3 +77,38 @@ impl AuthenticateClient for reqwest::RequestBuilder { .header("apikey", authenticator.apikey.clone()) } } + +trait DecodeStorageErrorResponse { + async fn decode_storage_error_response(self) -> crate::Result; +} + +impl DecodeStorageErrorResponse for reqwest::Response { + async fn decode_storage_error_response(self) -> crate::Result { + let status = self.status(); + if status.is_client_error() || status.is_server_error() { + let error = self.json::().await?; + Err(error.into()) + } else { + Ok(self) + } + } +} + +trait SendAndDecodeStorageRequest { + async fn send_and_decode_storage_request(self) -> crate::Result; +} + +impl SendAndDecodeStorageRequest for reqwest::RequestBuilder +where + Type: serde::de::DeserializeOwned, +{ + async fn send_and_decode_storage_request(self) -> crate::Result { + Ok(self + .send() + .await? + .decode_storage_error_response() + .await? + .json() + .await?) + } +} diff --git a/src/storage/object.rs b/src/storage/object.rs index f1f09ed..299c05c 100644 --- a/src/storage/object.rs +++ b/src/storage/object.rs @@ -1,4 +1,4 @@ -use crate::storage::AuthenticateClient; +use crate::storage::{AuthenticateClient, DecodeStorageErrorResponse, SendAndDecodeStorageRequest}; pub struct Object { pub(super) client: crate::storage::AuthenticatedClient, @@ -69,6 +69,11 @@ pub struct ObjectInformation { pub buckets: Option, } +#[derive(Debug, Clone, serde::Deserialize)] +pub struct SimpleMessage { + pub message: String, +} + /// Basic builder pattern for creating a request for listing objects. See more information /// [here](https://supabase.github.io/storage/#/object/post_object_list__bucketName_) impl ListRequest { @@ -107,16 +112,17 @@ impl ListRequest { } impl Object { /// Delete and object - pub async fn delete_one(self, bucket_name: &str, wildcard: &str) -> crate::Result { - Ok(self - .client + pub async fn delete_one( + self, + bucket_name: &str, + wildcard: &str, + ) -> crate::Result { + self.client .client .delete(format!("{}/{bucket_name}/{wildcard}", self.url_base)) .authenticate(&self.client) - .send() - .await? - .json() - .await?) + .send_and_decode_storage_request() + .await } /// Get object @@ -128,6 +134,8 @@ impl Object { .authenticate(&self.client) .send() .await? + .decode_storage_error_response() + .await? .bytes() .await? .to_vec()) @@ -153,7 +161,7 @@ impl Object { None => request, }; - Ok(request.send().await?.json().await?) + request.send_and_decode_storage_request().await } /// Upload a new object @@ -176,7 +184,7 @@ impl Object { None => request, }; - Ok(request.send().await?.json().await?) + request.send_and_decode_storage_request().await } /// Search for objects under a prefix @@ -185,15 +193,12 @@ impl Object { bucket_name: &str, request: ListRequest, ) -> crate::Result> { - Ok(self - .client + self.client .client .post(format!("{}/list/{bucket_name}", self.url_base)) .authenticate(&self.client) .json(&request) - .send() - .await? - .json() - .await?) + .send_and_decode_storage_request() + .await } }