Skip to content

Commit

Permalink
Add better error reporting from storage
Browse files Browse the repository at this point in the history
  • Loading branch information
strykejern committed Oct 19, 2024
1 parent 6fafbcc commit 35561c4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 16 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}")]
Expand Down
50 changes: 50 additions & 0 deletions src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<reqwest::Response>;
}

impl DecodeStorageErrorResponse for reqwest::Response {
async fn decode_storage_error_response(self) -> crate::Result<reqwest::Response> {
let status = self.status();
if status.is_client_error() || status.is_server_error() {
let error = self.json::<Error>().await?;
Err(error.into())
} else {
Ok(self)
}
}
}

trait SendAndDecodeStorageRequest<Type> {
async fn send_and_decode_storage_request(self) -> crate::Result<Type>;
}

impl<Type> SendAndDecodeStorageRequest<Type> for reqwest::RequestBuilder
where
Type: serde::de::DeserializeOwned,
{
async fn send_and_decode_storage_request(self) -> crate::Result<Type> {
Ok(self
.send()
.await?
.decode_storage_error_response()
.await?
.json()
.await?)
}
}
37 changes: 21 additions & 16 deletions src/storage/object.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::storage::AuthenticateClient;
use crate::storage::{AuthenticateClient, DecodeStorageErrorResponse, SendAndDecodeStorageRequest};

pub struct Object {
pub(super) client: crate::storage::AuthenticatedClient,
Expand Down Expand Up @@ -69,6 +69,11 @@ pub struct ObjectInformation {
pub buckets: Option<BucketInformation>,
}

#[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 {
Expand Down Expand Up @@ -107,16 +112,17 @@ impl ListRequest {
}
impl Object {
/// Delete and object
pub async fn delete_one(self, bucket_name: &str, wildcard: &str) -> crate::Result<String> {
Ok(self
.client
pub async fn delete_one(
self,
bucket_name: &str,
wildcard: &str,
) -> crate::Result<SimpleMessage> {
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
Expand All @@ -128,6 +134,8 @@ impl Object {
.authenticate(&self.client)
.send()
.await?
.decode_storage_error_response()
.await?
.bytes()
.await?
.to_vec())
Expand All @@ -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
Expand All @@ -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
Expand All @@ -185,15 +193,12 @@ impl Object {
bucket_name: &str,
request: ListRequest,
) -> crate::Result<Vec<ObjectInformation>> {
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
}
}

0 comments on commit 35561c4

Please sign in to comment.