2121
2222#include < string_view>
2323
24+ #include " iceberg/catalog/rest/json_serde_internal.h"
2425#include " iceberg/catalog/rest/types.h"
26+ #include " iceberg/json_serde_internal.h"
27+ #include " iceberg/util/json_util_internal.h"
28+ #include " iceberg/util/macros.h"
2529
2630namespace iceberg ::rest {
2731
@@ -31,8 +35,29 @@ constexpr std::string_view kIllegalArgumentException = "IllegalArgumentException
3135constexpr std::string_view kNoSuchNamespaceException = " NoSuchNamespaceException" ;
3236constexpr std::string_view kNamespaceNotEmptyException = " NamespaceNotEmptyException" ;
3337constexpr std::string_view kNoSuchTableException = " NoSuchTableException" ;
34- constexpr std::string_view kNoSuchPlanIdException = " NoSuchPlanIdException" ;
35- constexpr std::string_view kNoSuchPlanTaskException = " NoSuchPlanTaskException" ;
38+ constexpr std::string_view kNotFoundException = " NotFoundException" ;
39+ constexpr std::string_view kRestException = " RESTException" ;
40+ constexpr std::string_view kInvalidClient = " invalid_client" ;
41+ constexpr std::string_view kInvalidRequest = " invalid_request" ;
42+ constexpr std::string_view kInvalidGrant = " invalid_grant" ;
43+ constexpr std::string_view kUnauthorizedClient = " unauthorized_client" ;
44+ constexpr std::string_view kUnsupportedGrantType = " unsupported_grant_type" ;
45+ constexpr std::string_view kInvalidScope = " invalid_scope" ;
46+ constexpr std::string_view kNull = " null" ;
47+ constexpr std::string_view kOAuthError = " error" ;
48+ constexpr std::string_view kOAuthErrorDescription = " error_description" ;
49+
50+ std::string_view NullIfEmpty (const std::string& value) {
51+ if (value.empty ()) {
52+ return kNull ;
53+ }
54+ return value;
55+ }
56+
57+ Status CreateRestError (const ErrorResponse& error) {
58+ return RestError (" Unable to process (code: {}, type: {}): {}" , error.code ,
59+ NullIfEmpty (error.type ), NullIfEmpty (error.message ));
60+ }
3661
3762} // namespace
3863
@@ -63,7 +88,17 @@ Status DefaultErrorHandler::Accept(const ErrorResponse& error) const {
6388 return ServiceUnavailable (" Service unavailable: {}" , error.message );
6489 }
6590
66- return RestError (" Code: {}, message: {}" , error.code , error.message );
91+ return CreateRestError (error);
92+ }
93+
94+ Result<ErrorResponse> DefaultErrorHandler::ParseResponse (uint32_t /* code*/ ,
95+ const std::string& text) const {
96+ if (text.empty ()) {
97+ return InvalidArgument (" Empty response body" );
98+ }
99+ ICEBERG_ASSIGN_OR_RAISE (auto json_result, FromJsonString (text));
100+ ICEBERG_ASSIGN_OR_RAISE (auto error_result, ErrorResponseFromJson (json_result));
101+ return error_result;
67102}
68103
69104const std::shared_ptr<NamespaceErrorHandler>& NamespaceErrorHandler::Instance () {
@@ -84,7 +119,7 @@ Status NamespaceErrorHandler::Accept(const ErrorResponse& error) const {
84119 case 409 :
85120 return AlreadyExists (error.message );
86121 case 422 :
87- return RestError ( " Unable to process: {} " , error. message );
122+ return CreateRestError ( error);
88123 }
89124
90125 return DefaultErrorHandler::Accept (error);
@@ -104,37 +139,34 @@ Status DropNamespaceErrorHandler::Accept(const ErrorResponse& error) const {
104139 return NamespaceErrorHandler::Accept (error);
105140}
106141
107- const std::shared_ptr<TableErrorHandler >& TableErrorHandler ::Instance () {
108- static const std::shared_ptr<TableErrorHandler > instance{new TableErrorHandler ()};
142+ const std::shared_ptr<ConfigErrorHandler >& ConfigErrorHandler ::Instance () {
143+ static const std::shared_ptr<ConfigErrorHandler > instance{new ConfigErrorHandler ()};
109144 return instance;
110145}
111146
112- Status TableErrorHandler::Accept (const ErrorResponse& error) const {
113- switch (error.code ) {
114- case 404 :
115- if (error.type == kNoSuchNamespaceException ) {
116- return NoSuchNamespace (error.message );
117- }
118- return NoSuchTable (error.message );
119- case 409 :
120- return AlreadyExists (error.message );
147+ Status ConfigErrorHandler::Accept (const ErrorResponse& error) const {
148+ if (error.code == 404 && !error.type .empty () && error.type != kRestException ) {
149+ return NoSuchWarehouse (error.message );
121150 }
122151
123152 return DefaultErrorHandler::Accept (error);
124153}
125154
126- const std::shared_ptr<ViewErrorHandler >& ViewErrorHandler ::Instance () {
127- static const std::shared_ptr<ViewErrorHandler > instance{new ViewErrorHandler ()};
155+ const std::shared_ptr<TableErrorHandler >& TableErrorHandler ::Instance () {
156+ static const std::shared_ptr<TableErrorHandler > instance{new TableErrorHandler ()};
128157 return instance;
129158}
130159
131- Status ViewErrorHandler ::Accept (const ErrorResponse& error) const {
160+ Status TableErrorHandler ::Accept (const ErrorResponse& error) const {
132161 switch (error.code ) {
133162 case 404 :
134163 if (error.type == kNoSuchNamespaceException ) {
135164 return NoSuchNamespace (error.message );
136165 }
137- return NoSuchView (error.message );
166+ if (error.type == kNotFoundException ) {
167+ return NotFound (error.message );
168+ }
169+ return NoSuchTable (error.message );
138170 case 409 :
139171 return AlreadyExists (error.message );
140172 }
@@ -164,6 +196,23 @@ Status TableCommitErrorHandler::Accept(const ErrorResponse& error) const {
164196 return DefaultErrorHandler::Accept (error);
165197}
166198
199+ const std::shared_ptr<CreateTableErrorHandler>& CreateTableErrorHandler::Instance () {
200+ static const std::shared_ptr<CreateTableErrorHandler> instance{
201+ new CreateTableErrorHandler ()};
202+ return instance;
203+ }
204+
205+ Status CreateTableErrorHandler::Accept (const ErrorResponse& error) const {
206+ switch (error.code ) {
207+ case 404 :
208+ return NoSuchNamespace (error.message );
209+ case 409 :
210+ return AlreadyExists (error.message );
211+ }
212+
213+ return TableCommitErrorHandler::Accept (error);
214+ }
215+
167216const std::shared_ptr<ViewCommitErrorHandler>& ViewCommitErrorHandler::Instance () {
168217 static const std::shared_ptr<ViewCommitErrorHandler> instance{
169218 new ViewCommitErrorHandler ()};
@@ -186,6 +235,25 @@ Status ViewCommitErrorHandler::Accept(const ErrorResponse& error) const {
186235 return DefaultErrorHandler::Accept (error);
187236}
188237
238+ const std::shared_ptr<ViewErrorHandler>& ViewErrorHandler::Instance () {
239+ static const std::shared_ptr<ViewErrorHandler> instance{new ViewErrorHandler ()};
240+ return instance;
241+ }
242+
243+ Status ViewErrorHandler::Accept (const ErrorResponse& error) const {
244+ switch (error.code ) {
245+ case 404 :
246+ if (error.type == kNoSuchNamespaceException ) {
247+ return NoSuchNamespace (error.message );
248+ }
249+ return NoSuchView (error.message );
250+ case 409 :
251+ return AlreadyExists (error.message );
252+ }
253+
254+ return DefaultErrorHandler::Accept (error);
255+ }
256+
189257const std::shared_ptr<PlanErrorHandler>& PlanErrorHandler::Instance () {
190258 static const std::shared_ptr<PlanErrorHandler> instance{new PlanErrorHandler ()};
191259 return instance;
@@ -200,12 +268,7 @@ Status PlanErrorHandler::Accept(const ErrorResponse& error) const {
200268 if (error.type == kNoSuchTableException ) {
201269 return NoSuchTable (error.message );
202270 }
203- if (error.type == kNoSuchPlanIdException ) {
204- return NoSuchPlanId (error.message );
205- }
206- return NotFound (error.message );
207- case 406 :
208- return NotSupported (error.message );
271+ return NoSuchPlanId (error.message );
209272 }
210273
211274 return DefaultErrorHandler::Accept (error);
@@ -225,13 +288,49 @@ Status PlanTaskErrorHandler::Accept(const ErrorResponse& error) const {
225288 if (error.type == kNoSuchTableException ) {
226289 return NoSuchTable (error.message );
227290 }
228- if (error.type == kNoSuchPlanTaskException ) {
229- return NoSuchPlanTask (error.message );
230- }
231- return NotFound (error.message );
291+ return NoSuchPlanTask (error.message );
232292 }
233293
234294 return DefaultErrorHandler::Accept (error);
235295}
236296
297+ const std::shared_ptr<OAuthErrorHandler>& OAuthErrorHandler::Instance () {
298+ static const std::shared_ptr<OAuthErrorHandler> instance{new OAuthErrorHandler ()};
299+ return instance;
300+ }
301+
302+ Status OAuthErrorHandler::Accept (const ErrorResponse& error) const {
303+ if (!error.type .empty ()) {
304+ if (error.type == kInvalidClient ) {
305+ return NotAuthorized (" Not authorized: {}: {}" , error.type ,
306+ NullIfEmpty (error.message ));
307+ }
308+ if (error.type == kInvalidRequest || error.type == kInvalidGrant ||
309+ error.type == kUnauthorizedClient || error.type == kUnsupportedGrantType ||
310+ error.type == kInvalidScope ) {
311+ return BadRequest (" Malformed request: {}: {}" , error.type ,
312+ NullIfEmpty (error.message ));
313+ }
314+ }
315+
316+ return CreateRestError (error);
317+ }
318+
319+ Result<ErrorResponse> OAuthErrorHandler::ParseResponse (uint32_t code,
320+ const std::string& text) const {
321+ if (text.empty ()) {
322+ return InvalidArgument (" Empty response body" );
323+ }
324+
325+ ICEBERG_ASSIGN_OR_RAISE (auto json_result, FromJsonString (text));
326+
327+ ErrorResponse error;
328+ error.code = code;
329+ ICEBERG_ASSIGN_OR_RAISE (error.type ,
330+ GetJsonValue<std::string>(json_result, kOAuthError ));
331+ ICEBERG_ASSIGN_OR_RAISE (error.message , GetJsonValueOrDefault<std::string>(
332+ json_result, kOAuthErrorDescription ));
333+ return error;
334+ }
335+
237336} // namespace iceberg::rest
0 commit comments