From fe4ad979ab1b127ed1bd3123d7f7d53e7f0daad3 Mon Sep 17 00:00:00 2001 From: Pavan Manish Date: Mon, 9 Dec 2024 15:38:52 +0530 Subject: [PATCH 1/3] feat: Enhance error handling with detailed cause reporting --- atlan/assets/errors.go | 52 ++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/atlan/assets/errors.go b/atlan/assets/errors.go index 9b4a77b..bc6aad1 100644 --- a/atlan/assets/errors.go +++ b/atlan/assets/errors.go @@ -3,6 +3,8 @@ package assets import ( "fmt" "net/http" + "io" + "encoding/json" ) type ErrorInfo struct { @@ -152,8 +154,8 @@ var errorCodes = map[ErrorCode]ErrorInfo{ INVALID_REQUEST_PASSTHROUGH: { HTTPErrorCode: 400, ErrorID: "ATLAN-GO-400-000", - ErrorMessage: "Server responded with %s: %s. Check the details of the server's message to correct your request.", - UserAction: "", + ErrorMessage: "Server responded with %s: %s.%s", + UserAction: "Check the details of the server's message to correct your request.", }, MISSING_GROUP_ID: { HTTPErrorCode: 400, @@ -482,7 +484,7 @@ var errorCodes = map[ErrorCode]ErrorInfo{ PERMISSION_PASSTHROUGH: { HTTPErrorCode: 403, ErrorID: "ATLAN-GO-403-000", - ErrorMessage: "Server responded with %s: %s", + ErrorMessage: "Server responded with %s: %s.%s", UserAction: "Check the details of the server's message to correct your request.", }, UNABLE_TO_IMPERSONATE: { @@ -500,7 +502,7 @@ var errorCodes = map[ErrorCode]ErrorInfo{ NOT_FOUND_PASSTHROUGH: { HTTPErrorCode: 404, ErrorID: "ATLAN-GO-404-000", - ErrorMessage: "Server responded with %s: %s", + ErrorMessage: "Server responded with %s: %s.%s", UserAction: "Check the details of the server's message to correct your request.", }, ASSET_NOT_FOUND_BY_GUID: { @@ -668,7 +670,7 @@ var errorCodes = map[ErrorCode]ErrorInfo{ CONFLICT_PASSTHROUGH: { HTTPErrorCode: 409, ErrorID: "ATLAN-GO-409-000", - ErrorMessage: "Server responded with %s: %s", + ErrorMessage: "Server responded with %s: %s.%s", UserAction: "Check the details of the server's message to correct your request.", }, RESERVED_SERVICE_TYPE: { @@ -680,13 +682,13 @@ var errorCodes = map[ErrorCode]ErrorInfo{ RATE_LIMIT_PASSTHROUGH: { HTTPErrorCode: 429, ErrorID: "ATLAN-GO-429-000", - ErrorMessage: "Server responded with %s: %s", + ErrorMessage: "Server responded with %s: %s.%s", UserAction: "Check the details of the server's message to correct your request.", }, ERROR_PASSTHROUGH: { HTTPErrorCode: 500, ErrorID: "ATLAN-GO-500-000", - ErrorMessage: "Server responded with %s: %s", + ErrorMessage: "Server responded with %s: %s.%s", UserAction: "Check the details of the server's message to correct your request.", }, DUPLICATE_CUSTOM_ATTRIBUTES: { @@ -727,27 +729,49 @@ var errorCodes = map[ErrorCode]ErrorInfo{ }, } + +type Cause struct { + ErrorType string `json:"errorType"` + ErrorMessage string `json:"errorMessage"` + Location string `json:"location"` +} + +type ErrorResponse struct { + Causes []Cause `json:"causes"` + ErrorID string `json:"errorId"` + Message string `json:"message"` +} + func handleApiError(response *http.Response, originalError error) error { if response == nil { return ThrowAtlanError(originalError, CONNECTION_ERROR, nil) } rc := response.StatusCode + causesString := "" + body, _ := io.ReadAll(response.Body) + var errorResponse ErrorResponse + if err := json.Unmarshal(body, &errorResponse); err == nil { + for _, cause := range errorResponse.Causes { + causesString += fmt.Sprintf(" %s : %s : %s \n", cause.ErrorType, cause.ErrorMessage, cause.Location) + } + } + switch rc { case 400: - return ThrowAtlanError(originalError, INVALID_REQUEST_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, INVALID_REQUEST_PASSTHROUGH, nil, causesString) case 404: - return ThrowAtlanError(originalError, NOT_FOUND_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, NOT_FOUND_PASSTHROUGH, nil, causesString) case 401: - return ThrowAtlanError(originalError, AUTHENTICATION_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, AUTHENTICATION_PASSTHROUGH, nil, causesString) case 403: - return ThrowAtlanError(originalError, PERMISSION_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, PERMISSION_PASSTHROUGH, nil, causesString) case 409: - return ThrowAtlanError(originalError, CONFLICT_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, CONFLICT_PASSTHROUGH, nil, causesString) case 429: - return ThrowAtlanError(originalError, RATE_LIMIT_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, RATE_LIMIT_PASSTHROUGH, nil, causesString) default: - return ThrowAtlanError(originalError, ERROR_PASSTHROUGH, nil) + return ThrowAtlanError(originalError, ERROR_PASSTHROUGH, nil, causesString) } } From 8fd3c72a87b92b3b463aa751cc96874510d7dfab Mon Sep 17 00:00:00 2001 From: Karanjot Singh Date: Sat, 28 Dec 2024 21:16:49 +0530 Subject: [PATCH 2/3] fix: Not_FOUND_PASSTHROUGH does not include error cause Signed-off-by: Karanjot Singh --- atlan/assets/errors.go | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/atlan/assets/errors.go b/atlan/assets/errors.go index bc6aad1..8fcf5e0 100644 --- a/atlan/assets/errors.go +++ b/atlan/assets/errors.go @@ -1,10 +1,10 @@ package assets import ( + "encoding/json" "fmt" - "net/http" "io" - "encoding/json" + "net/http" ) type ErrorInfo struct { @@ -502,7 +502,7 @@ var errorCodes = map[ErrorCode]ErrorInfo{ NOT_FOUND_PASSTHROUGH: { HTTPErrorCode: 404, ErrorID: "ATLAN-GO-404-000", - ErrorMessage: "Server responded with %s: %s.%s", + ErrorMessage: "Server responded with %s: %s.", UserAction: "Check the details of the server's message to correct your request.", }, ASSET_NOT_FOUND_BY_GUID: { @@ -729,17 +729,16 @@ var errorCodes = map[ErrorCode]ErrorInfo{ }, } - type Cause struct { - ErrorType string `json:"errorType"` - ErrorMessage string `json:"errorMessage"` - Location string `json:"location"` + ErrorType string `json:"errorType"` + ErrorMessage string `json:"errorMessage"` + Location string `json:"location"` } type ErrorResponse struct { - Causes []Cause `json:"causes"` - ErrorID string `json:"errorId"` - Message string `json:"message"` + Causes []Cause `json:"causes"` + ErrorID string `json:"errorId"` + Message string `json:"message"` } func handleApiError(response *http.Response, originalError error) error { @@ -749,13 +748,13 @@ func handleApiError(response *http.Response, originalError error) error { rc := response.StatusCode causesString := "" - body, _ := io.ReadAll(response.Body) - var errorResponse ErrorResponse - if err := json.Unmarshal(body, &errorResponse); err == nil { - for _, cause := range errorResponse.Causes { - causesString += fmt.Sprintf(" %s : %s : %s \n", cause.ErrorType, cause.ErrorMessage, cause.Location) - } - } + body, _ := io.ReadAll(response.Body) + var errorResponse ErrorResponse + if err := json.Unmarshal(body, &errorResponse); err == nil { + for _, cause := range errorResponse.Causes { + causesString += fmt.Sprintf(" %s : %s : %s \n", cause.ErrorType, cause.ErrorMessage, cause.Location) + } + } switch rc { case 400: From 88a96c9099fff44c864780d821d4ffc1662595ea Mon Sep 17 00:00:00 2001 From: Karanjot Singh Date: Sat, 28 Dec 2024 21:46:45 +0530 Subject: [PATCH 3/3] fix: handle error formatting and causes parsing Signed-off-by: Karanjot Singh --- atlan/assets/errors.go | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/atlan/assets/errors.go b/atlan/assets/errors.go index 8fcf5e0..7445da2 100644 --- a/atlan/assets/errors.go +++ b/atlan/assets/errors.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "strings" ) type ErrorInfo struct { @@ -17,8 +18,8 @@ type ErrorInfo struct { type AtlanError struct { ErrorCode ErrorInfo Args []interface{} - OriginalError string // Error received from Atlan API - + OriginalError string // Error received from Atlan API + Causes []Cause // List of causes from API response } func (e AtlanError) Error() string { @@ -29,6 +30,13 @@ func (e AtlanError) Error() string { if e.OriginalError != "" { errorMessage += "\nError response from server: " + e.OriginalError } + + if len(e.Causes) > 0 { + errorMessage += "\nCauses:\n" + for _, cause := range e.Causes { + errorMessage += fmt.Sprintf("- %s: %s (Location: %s)\n", cause.ErrorType, cause.ErrorMessage, cause.Location) + } + } return errorMessage } @@ -746,12 +754,17 @@ func handleApiError(response *http.Response, originalError error) error { return ThrowAtlanError(originalError, CONNECTION_ERROR, nil) } rc := response.StatusCode - - causesString := "" body, _ := io.ReadAll(response.Body) var errorResponse ErrorResponse + var causes []Cause + if err := json.Unmarshal(body, &errorResponse); err == nil { - for _, cause := range errorResponse.Causes { + fmt.Println(errorResponse) + causes = errorResponse.Causes + } + var causesString string + if len(causes) > 0 { + for _, cause := range causes { causesString += fmt.Sprintf(" %s : %s : %s \n", cause.ErrorType, cause.ErrorMessage, cause.Location) } } @@ -791,10 +804,13 @@ func ThrowAtlanError(err error, sdkError ErrorCode, suggestion *string, args ... atlanError.ErrorCode.UserAction = *suggestion } - if len(args) != 0 { - atlanError.ErrorCode.ErrorMessage = fmt.Sprintf( - atlanError.ErrorCode.ErrorMessage, atlanError.Args..., - ) + if len(args) > 0 { + if strings.Contains(atlanError.ErrorCode.ErrorMessage, "%") { + atlanError.ErrorCode.ErrorMessage = fmt.Sprintf( + atlanError.ErrorCode.ErrorMessage, args..., + ) + } + atlanError.Args = args } return &atlanError