Xuanwo commented on code in PR #965:
URL: https://github.com/apache/iceberg-rust/pull/965#discussion_r1957506030


##########
crates/catalog/rest/src/catalog.rs:
##########
@@ -312,90 +317,107 @@ impl RestCatalog {
     }
 }
 
+/// All requests and expected responses are derived from the REST catalog API 
spec:
+/// 
https://github.com/apache/iceberg/blob/main/open-api/rest-catalog-open-api.yaml
 #[async_trait]
 impl Catalog for RestCatalog {
-    /// List namespaces from table.
     async fn list_namespaces(
         &self,
         parent: Option<&NamespaceIdent>,
     ) -> Result<Vec<NamespaceIdent>> {
-        let mut request = self.context().await?.client.request(
-            Method::GET,
-            self.context().await?.config.namespaces_endpoint(),
-        );
-        if let Some(ns) = parent {
-            request = request.query(&[("parent", ns.to_url_string())]);
-        }
+        let context = self.context().await?;
 
-        let resp = self
-            .context()
-            .await?
+        let mut request_builder = context
             .client
-            .query::<ListNamespaceResponse, ErrorResponse>(request.build()?)
-            .await?;
+            .request(Method::GET, context.config.namespaces_endpoint());
+        // Filter on `parent={namespace}` if a parent namespace exists.
+        if let Some(namespace) = parent {
+            request_builder = request_builder.query(&[("parent", 
namespace.to_url_string())]);
+        }
+        let request = request_builder.build()?;
+
+        let handler = |response: Response| async move {
+            match response.status() {
+                StatusCode::OK => {
+                    
Ok(deserialize_catalog_response::<ListNamespaceResponse>(response).await?)
+                }
+                StatusCode::NOT_FOUND => Err(Error::new(
+                    ErrorKind::Unexpected,

Review Comment:
   This change made me think about how users can handle cases where the 
namespace doesn't exist. Maybe we should add an `ErrorKind::NamespaceNotExists`?
   
   Maybe this should be done in another PR.



##########
crates/catalog/rest/src/catalog.rs:
##########
@@ -507,78 +530,98 @@ impl Catalog for RestCatalog {
             })
             .build()?;
 
-        let resp = self
-            .context()
-            .await?
-            .client
-            .query::<LoadTableResponse, ErrorResponse>(request)
-            .await?;
+        let handler = |response: Response| async move {
+            match response.status() {
+                StatusCode::OK => {
+                    
Ok(deserialize_catalog_response::<LoadTableResponse>(response).await?)
+                }
+                StatusCode::NOT_FOUND => Err(Error::new(
+                    ErrorKind::Unexpected,
+                    "Tried to create a table under a namespace that does not 
exist",
+                )),
+                StatusCode::CONFLICT => Err(Error::new(
+                    ErrorKind::Unexpected,

Review Comment:
   The same question, maybe we should have `TableNotFound` nad 
`TableAlreadyExists`.



##########
crates/catalog/rest/src/catalog.rs:
##########
@@ -670,21 +719,47 @@ impl Catalog for RestCatalog {
             })
             .build()?;
 
-        let resp = self
-            .context()
-            .await?
-            .client
-            .query::<CommitTableResponse, ErrorResponse>(request)
-            .await?;
+        let handler = |response: Response| async move {
+            if response.status() == StatusCode::OK {
+                return 
deserialize_catalog_response::<CommitTableResponse>(response).await;
+            }
+
+            let error_message = match response.status() {
+                StatusCode::NOT_FOUND => "Tried to update a table that does 
not exist",
+                StatusCode::CONFLICT => {
+                    "CommitFailedException, one or more requirements failed. 
The client may retry."
+                }
+                StatusCode::INTERNAL_SERVER_ERROR => {
+                    "An unknown server-side problem occurred; the commit state 
is unknown."
+                }
+                StatusCode::BAD_GATEWAY => {
+                    "A gateway or proxy received an invalid response from the 
upstream server; the commit state is unknown."
+                }
+                StatusCode::GATEWAY_TIMEOUT => {
+                    "A server-side gateway timeout occurred; the commit state 
is unknown."
+                }
+                _ => {
+                    return Err(deserialize_unexpected_catalog_error(
+                        response,
+                    )
+                    .await);
+                }
+            };
+
+            Err(Error::new(ErrorKind::Unexpected, error_message))
+        };
+
+        let response = context.client.query_catalog(request, handler).await?;

Review Comment:
   To be honest, I don't like the style of creating a handle and passing it 
into another function. It usually breaks the logical flow and makes it hard to 
understand what’s happening.
   
   It's easy to understand that:
   
   ```rust
   let resp = self
           .context()
           .await?
           .client
           .query::<CommitTableResponse, ErrorResponse>(request)
           .await?;
   ```
   
   Ok, the client will perform query and returns a response or error.
   
   But it's hard to:
   
   ```rust
   let handler = |response: Response| async move { ... };
   let response = context.client.query_catalog(request, handler).await?;
   ```
   
   Let's build a handler and it will do something to the response. Remember 
this funcation now. The client will perform query catalog and use the previous 
handler to parse the response. Emmmm, wait a second, what does this handler do?
   
   ---
   
   How about taking a step back and simply returning an HTTP response in those 
functions? That way, we have full control over handling the HTTP response here. 
We only have a limited number of APIs to implement, and they won’t grow 
quickly. I’m fine with just writing them directly instead of adding generics or 
callbacks.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org
For additional commands, e-mail: issues-h...@iceberg.apache.org

Reply via email to