diff --git a/apierror/apierror.go b/apierror/apierror.go index 7355869..02fbd2d 100644 --- a/apierror/apierror.go +++ b/apierror/apierror.go @@ -5,6 +5,8 @@ package apierror import ( "errors" "fmt" + "log/slog" + "net/http" apiClient "github.com/smartcontractkit/crec-api-go/client" ) @@ -14,6 +16,11 @@ import ( // ApplicationError of type ORGANIZATION_NOT_FOUND). var ErrOrganizationNotFound = errors.New("organization not found") +// ErrPermissionDenied is returned when the CREC API reports that the +// authenticated principal lacks the required permission for the operation +// (HTTP 403 with an ApplicationError of type PERMISSION_DENIED). +var ErrPermissionDenied = errors.New("permission denied") + // Canonical not-found sentinels for HTTP 404 responses. The API disambiguates // which resource was missing via ApplicationError.code. Packages that assign // these variables (rather than defining their own) share the same sentinel @@ -67,6 +74,8 @@ func FromApplicationError(appErr *apiClient.ApplicationError) error { switch appErr.Type { case apiClient.ORGANIZATIONNOTFOUND: return ErrOrganizationNotFound + case apiClient.PERMISSIONDENIED: + return ErrPermissionDenied default: return nil } @@ -83,6 +92,36 @@ func Wrap(appErr *apiClient.ApplicationError, opErr error, statusCode int) error return fmt.Errorf("%w: %w (status code %d)", opErr, ErrUnexpectedStatusCode, statusCode) } +// HandleErrorStatus handles the common HTTP error cases shared across all SDK endpoints. +// Endpoints handle their success and specific cases (404, 409, 429, etc.) in +// their own switch and delegate the remaining cases to this helper via default. +func HandleErrorStatus( + statusCode int, + json401, json403 *apiClient.ApplicationError, + opErr error, + opDesc string, + body []byte, + logger *slog.Logger, +) error { + switch statusCode { + case http.StatusForbidden: + logger.Error("Permission denied when "+opDesc, + "status_code", statusCode, + "body", string(body)) + return Wrap(json403, opErr, statusCode) + case http.StatusUnauthorized: + logger.Error("Unauthorized when "+opDesc, + "status_code", statusCode, + "body", string(body)) + return Wrap(json401, opErr, statusCode) + default: + logger.Error("Unexpected status code when "+opDesc, + "status_code", statusCode, + "body", string(body)) + return fmt.Errorf("%w: %w (status code %d)", opErr, ErrUnexpectedStatusCode, statusCode) + } +} + // NotFound maps a 404 ApplicationError to its canonical not-found sentinel based // on ApplicationError.code, or returns nil when the code is missing or // unrecognized (forward-compatible for codes added after this SDK release). diff --git a/apierror/apierror_test.go b/apierror/apierror_test.go index b7e3338..a175b3e 100644 --- a/apierror/apierror_test.go +++ b/apierror/apierror_test.go @@ -2,6 +2,7 @@ package apierror_test import ( "errors" + "log/slog" "net/http" "testing" @@ -28,6 +29,11 @@ func TestApierror_FromApplicationError(t *testing.T) { appErr: &apiClient.ApplicationError{Type: apiClient.ORGANIZATIONNOTFOUND, Message: "organization not found"}, wantErr: apierror.ErrOrganizationNotFound, }, + { + name: "permission denied maps to sentinel", + appErr: &apiClient.ApplicationError{Type: apiClient.PERMISSIONDENIED, Message: "principal lacks permission crec:wallet:create"}, + wantErr: apierror.ErrPermissionDenied, + }, { name: "unknown future type degrades to nil", appErr: &apiClient.ApplicationError{Type: "SOME_FUTURE_TYPE", Message: "new"}, @@ -209,6 +215,15 @@ func TestApierror_Wrap(t *testing.T) { assert.NotErrorIs(t, err, apierror.ErrUnexpectedStatusCode) }) + t.Run("permission denied wraps opErr", func(t *testing.T) { + appErr := &apiClient.ApplicationError{Type: apiClient.PERMISSIONDENIED, Message: "principal lacks permission crec:wallet:create"} + err := apierror.Wrap(appErr, opErr, http.StatusForbidden) + + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrPermissionDenied) + assert.NotErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) + t.Run("unmapped type falls back to unexpected-status error", func(t *testing.T) { appErr := &apiClient.ApplicationError{Type: "SOME_FUTURE_TYPE", Message: "new"} err := apierror.Wrap(appErr, opErr, http.StatusUnauthorized) @@ -226,6 +241,50 @@ func TestApierror_Wrap(t *testing.T) { }) } +func TestApierror_HandleErrorStatus(t *testing.T) { + opErr := errors.New("failed to create wallet") + logger := slog.New(slog.DiscardHandler) + + t.Run("403 with PERMISSION_DENIED wraps with ErrPermissionDenied", func(t *testing.T) { + json403 := &apiClient.ApplicationError{Type: apiClient.PERMISSIONDENIED, Message: "principal lacks permission crec:wallet:create"} + err := apierror.HandleErrorStatus(http.StatusForbidden, nil, json403, opErr, "creating wallet", []byte("body"), logger) + + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrPermissionDenied) + assert.NotErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) + + t.Run("401 with ORGANIZATION_NOT_FOUND wraps with ErrOrganizationNotFound", func(t *testing.T) { + json401 := &apiClient.ApplicationError{Type: apiClient.ORGANIZATIONNOTFOUND, Message: "organization not found"} + err := apierror.HandleErrorStatus(http.StatusUnauthorized, json401, nil, opErr, "creating wallet", []byte("body"), logger) + + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrOrganizationNotFound) + assert.NotErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) + + t.Run("401 with unmapped type falls back to ErrUnexpectedStatusCode", func(t *testing.T) { + json401 := &apiClient.ApplicationError{Type: "SOME_FUTURE_TYPE", Message: "new"} + err := apierror.HandleErrorStatus(http.StatusUnauthorized, json401, nil, opErr, "creating wallet", []byte("body"), logger) + + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) + + t.Run("500 falls back to ErrUnexpectedStatusCode", func(t *testing.T) { + err := apierror.HandleErrorStatus(http.StatusInternalServerError, nil, nil, opErr, "creating wallet", []byte("body"), logger) + + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) + + t.Run("nil json401 and json403 do not panic", func(t *testing.T) { + err := apierror.HandleErrorStatus(http.StatusUnauthorized, nil, nil, opErr, "creating wallet", nil, logger) + assert.ErrorIs(t, err, opErr) + assert.ErrorIs(t, err, apierror.ErrUnexpectedStatusCode) + }) +} + func TestApierror_Conflict(t *testing.T) { channelCode := apiClient.ApplicationErrorCodeChannelAlreadyExists walletCode := apiClient.ApplicationErrorCodeWalletAlreadyExists diff --git a/channels/channels.go b/channels/channels.go index ede84bb..7182252 100644 --- a/channels/channels.go +++ b/channels/channels.go @@ -144,16 +144,8 @@ func (c *Client) Create(ctx context.Context, input CreateInput) (*apiClient.Chan "name", input.Name, "code", apierror.ConflictCode(resp.JSON409)) return nil, apierror.WrapConflict(resp.JSON409, ErrCreateChannel, "name "+input.Name) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when creating channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrCreateChannel, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when creating channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrCreateChannel, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateChannel, "creating channel", resp.Body, c.logger) } } @@ -193,16 +185,8 @@ func (c *Client) Get(ctx context.Context, channelID uuid.UUID) (*apiClient.Chann "code", apierror.NotFoundCode(resp.JSON404), ) return nil, fmt.Errorf("%w: channel ID %s", ErrChannelNotFound, channelID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when getting channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrGetChannel, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when getting channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrGetChannel, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrGetChannel, "getting channel", resp.Body, c.logger) } } @@ -254,16 +238,8 @@ func (c *Client) List(ctx context.Context, input ListInput) ([]apiClient.Channel "count", len(resp.JSON200.Data), "has_more", resp.JSON200.HasMore) return resp.JSON200.Data, resp.JSON200.HasMore, nil - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when listing channels", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, apierror.Wrap(resp.JSON401, ErrListChannels, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when listing channels", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, fmt.Errorf("%w: %w (status code %d)", ErrListChannels, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListChannels, "listing channels", resp.Body, c.logger) } } @@ -326,16 +302,8 @@ func (c *Client) Update(ctx context.Context, channelID uuid.UUID, input UpdateIn "channel_id", channelID.String(), "code", apierror.ConflictCode(resp.JSON409)) return nil, apierror.WrapConflict(resp.JSON409, ErrUpdateChannel, "channel ID "+channelID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when updating channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrUpdateChannel, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when updating channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrUpdateChannel, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrUpdateChannel, "updating channel", resp.Body, c.logger) } } @@ -380,15 +348,7 @@ func (c *Client) Archive(ctx context.Context, channelID uuid.UUID) (*apiClient.C "code", apierror.NotFoundCode(resp.JSON404), ) return nil, fmt.Errorf("%w: channel ID %s", ErrChannelNotFound, channelID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when archiving channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrArchiveChannel, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when archiving channel", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrArchiveChannel, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrArchiveChannel, "archiving channel", resp.Body, c.logger) } } diff --git a/crec.go b/crec.go index 9730df3..5f57949 100644 --- a/crec.go +++ b/crec.go @@ -270,18 +270,7 @@ func (c *Client) ListNetworks(ctx context.Context) ([]apiClient.Network, bool, e return nil, false, ErrListNetworks } return resp.JSON200.Data, resp.JSON200.HasMore, nil - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when listing networks", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - if mapped := apierror.FromApplicationError(resp.JSON401); mapped != nil { - return nil, false, fmt.Errorf("%w: %w", ErrListNetworks, mapped) - } - return nil, false, fmt.Errorf("%w (status code %d)", ErrListNetworks, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when listing networks", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, fmt.Errorf("%w (status code %d)", ErrListNetworks, resp.StatusCode()) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListNetworks, "listing networks", resp.Body, c.logger) } } diff --git a/events/events.go b/events/events.go index 83ee773..93ee4d3 100644 --- a/events/events.go +++ b/events/events.go @@ -288,22 +288,8 @@ func (c *Client) Poll( return nil, false, apierror.WrapChannelNotFound( resp.JSON404, ErrPollEvents, "channel ID "+channelID.String(), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to get events - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, false, apierror.Wrap(resp.JSON401, ErrPollEvents, resp.StatusCode()) default: - c.logger.Error( - "Failed to get events - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, false, fmt.Errorf( - "%w: %w (status code %d)", ErrPollEvents, apierror.ErrUnexpectedStatusCode, resp.StatusCode(), - ) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrPollEvents, "polling events", resp.Body, c.logger) } } @@ -370,22 +356,8 @@ func (c *Client) SearchEvents( return nil, false, fmt.Errorf( "%w: %w: %s (status code %d)", ErrSearchEvents, ErrBadRequest, errorMsg, resp.StatusCode(), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to search events - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, false, apierror.Wrap(resp.JSON401, ErrSearchEvents, resp.StatusCode()) default: - c.logger.Error( - "Failed to search events - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, false, fmt.Errorf( - "%w: %w (status code %d)", ErrSearchEvents, apierror.ErrUnexpectedStatusCode, resp.StatusCode(), - ) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrSearchEvents, "searching events", resp.Body, c.logger) } } diff --git a/go.mod b/go.mod index ded37fc..99ec0af 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/oapi-codegen/runtime v1.1.2 github.com/smartcontractkit/chain-selectors v1.0.89 github.com/smartcontractkit/chainlink-common v0.10.0 - github.com/smartcontractkit/crec-api-go v0.8.0-rc3 + github.com/smartcontractkit/crec-api-go v0.8.0-rc2 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.38.0 github.com/testcontainers/testcontainers-go/modules/vault v0.38.0 diff --git a/go.sum b/go.sum index d2501fc..2338709 100644 --- a/go.sum +++ b/go.sum @@ -435,8 +435,8 @@ github.com/smartcontractkit/chainlink-common v0.10.0 h1:d90b9UPJecrIryzhl43F1oQw github.com/smartcontractkit/chainlink-common v0.10.0/go.mod h1:13YN2kb3Vqpw2S7d4IwhX/578WPGC0JHN5JrOnAEsOc= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260210221717-2546aed27ebe h1:Vc4zoSc/j6/FdCQ7vcyHTTB7kzHI2f+lHCHqFuiCcJQ= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260210221717-2546aed27ebe/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/crec-api-go v0.8.0-rc3 h1:9s1A23U2l3yabB479Kp1dNDmMCXBFk0/HHRwoDRoClI= -github.com/smartcontractkit/crec-api-go v0.8.0-rc3/go.mod h1:y91qqcZFtWiKLFu66c/dmBp10bTzcpGcb4XFR7eLknk= +github.com/smartcontractkit/crec-api-go v0.8.0-rc2 h1:YuhcGkl8/1umaFiw718ahIb1+eJds4QFdWbrUd7472o= +github.com/smartcontractkit/crec-api-go v0.8.0-rc2/go.mod h1:y91qqcZFtWiKLFu66c/dmBp10bTzcpGcb4XFR7eLknk= github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d h1:LokA9PoCNb8mm8mDT52c3RECPMRsGz1eCQORq+J3n74= github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= diff --git a/queries/queries.go b/queries/queries.go index 3755048..ff299bd 100644 --- a/queries/queries.go +++ b/queries/queries.go @@ -312,16 +312,8 @@ func (c *Client) Create(ctx context.Context, input CreateInput) (*apiClient.Quer ) case http.StatusTooManyRequests: return nil, fmt.Errorf("%w: %w", ErrCreateQuery, ErrRateLimitExceeded) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when creating query", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrCreateQuery, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when creating query", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrCreateQuery, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateQuery, "creating query", resp.Body, c.logger) } } @@ -378,16 +370,8 @@ func (c *Client) Get(ctx context.Context, channelID uuid.UUID, queryID uuid.UUID ErrGetQuery, fmt.Sprintf("channel ID %s, query ID %s", channelID.String(), queryID.String()), ) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when getting query", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrGetQuery, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when getting query", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrGetQuery, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrGetQuery, "getting query", resp.Body, c.logger) } } @@ -435,16 +419,8 @@ func (c *Client) List(ctx context.Context, input ListInput) ([]apiClient.Query, return nil, false, apierror.WrapChannelNotFound( resp.JSON404, ErrListQueries, "channel ID "+input.ChannelID.String(), ) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when listing queries", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, apierror.Wrap(resp.JSON401, ErrListQueries, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when listing queries", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, fmt.Errorf("%w: %w (status code %d)", ErrListQueries, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListQueries, "listing queries", resp.Body, c.logger) } } diff --git a/transact/transact.go b/transact/transact.go index af533e7..902a8c2 100644 --- a/transact/transact.go +++ b/transact/transact.go @@ -267,16 +267,8 @@ func (c *Client) postCreateOperation( channelID.String(), createReq.Address, createReq.ChainSelector, walletOperationID, ) return nil, apierror.WrapConflict(resp.JSON409, ErrCreateOperation, conflictDetail) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when creating operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrCreateOperation, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when creating operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrCreateOperation, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateOperation, "creating operation", resp.Body, c.logger) } } @@ -550,16 +542,8 @@ func (c *Client) GetOperation(ctx context.Context, channelID uuid.UUID, operatio ErrGetOperation, fmt.Sprintf("channel ID %s, operation ID %s", channelID.String(), operationID.String()), ) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when getting operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrGetOperation, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when getting operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrGetOperation, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrGetOperation, "getting operation", resp.Body, c.logger) } } @@ -637,16 +621,8 @@ func (c *Client) ListOperations(ctx context.Context, input ListOperationsInput) return nil, false, apierror.WrapChannelNotFound( resp.JSON404, ErrListOperations, "channel ID "+input.ChannelID.String(), ) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when listing operations", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, apierror.Wrap(resp.JSON401, ErrListOperations, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when listing operations", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, fmt.Errorf("%w: %w (status code %d)", ErrListOperations, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListOperations, "listing operations", resp.Body, c.logger) } } @@ -767,16 +743,8 @@ func (c *Client) SendSignedDraftOperation( return nil, ErrDraftNotFound case http.StatusConflict: return nil, apierror.WrapConflict(resp.JSON409, ErrDraftNotFinalizable, "operation ID "+operationID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when sending operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrSendOperation, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when sending operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrSendOperation, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrSendOperation, "sending operation", resp.Body, c.logger) } } @@ -836,15 +804,7 @@ func (c *Client) CancelDraftOperation(ctx context.Context, channelID uuid.UUID, return ErrDraftNotFound case http.StatusConflict: return apierror.WrapConflict(resp.JSON409, ErrDraftNotCancellable, "operation ID "+operationID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when cancelling operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return apierror.Wrap(resp.JSON401, ErrSendOperation, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when cancelling operation", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return fmt.Errorf("%w: %w (status code %d)", ErrSendOperation, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrSendOperation, "cancelling operation", resp.Body, c.logger) } } diff --git a/wallets/wallets.go b/wallets/wallets.go index a793ad3..4bc5bfa 100644 --- a/wallets/wallets.go +++ b/wallets/wallets.go @@ -199,16 +199,8 @@ func (c *Client) Create(ctx context.Context, input CreateInput) (*apiClient.Wall "name", input.Name, "code", apierror.ConflictCode(resp.JSON409)) return nil, apierror.WrapConflict(resp.JSON409, ErrCreateWallet, "name "+input.Name) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when creating wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrCreateWallet, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when creating wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrCreateWallet, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateWallet, "creating wallet", resp.Body, c.logger) } } @@ -253,16 +245,8 @@ func (c *Client) Get(ctx context.Context, walletID uuid.UUID) (*apiClient.Wallet "code", apierror.NotFoundCode(resp.JSON404), ) return nil, fmt.Errorf("%w: wallet ID %s", ErrWalletNotFound, walletID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when getting wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, apierror.Wrap(resp.JSON401, ErrGetWallet, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when getting wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrGetWallet, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrGetWallet, "getting wallet", resp.Body, c.logger) } } @@ -349,16 +333,8 @@ func (c *Client) List(ctx context.Context, input ListInput) ([]apiClient.Wallet, "count", len(resp.JSON200.Data), "has_more", resp.JSON200.HasMore) return resp.JSON200.Data, resp.JSON200.HasMore, nil - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when listing wallets", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, apierror.Wrap(resp.JSON401, ErrListWallets, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when listing wallets", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return nil, false, fmt.Errorf("%w: %w (status code %d)", ErrListWallets, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, false, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListWallets, "listing wallets", resp.Body, c.logger) } } @@ -421,16 +397,8 @@ func (c *Client) Update(ctx context.Context, walletID uuid.UUID, input UpdateInp "wallet_id", walletID.String(), "code", apierror.ConflictCode(resp.JSON409)) return apierror.WrapConflict(resp.JSON409, ErrUpdateWallet, "wallet ID "+walletID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when updating wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return apierror.Wrap(resp.JSON401, ErrUpdateWallet, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when updating wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return fmt.Errorf("%w: %w (status code %d)", ErrUpdateWallet, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrUpdateWallet, "updating wallet", resp.Body, c.logger) } } @@ -475,15 +443,7 @@ func (c *Client) Archive(ctx context.Context, walletID uuid.UUID) error { "code", apierror.NotFoundCode(resp.JSON404), ) return fmt.Errorf("%w: wallet ID %s", ErrWalletNotFound, walletID.String()) - case http.StatusUnauthorized: - c.logger.Error("Unauthorized when archiving wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return apierror.Wrap(resp.JSON401, ErrArchiveWallet, resp.StatusCode()) default: - c.logger.Error("Unexpected status code when archiving wallet", - "status_code", resp.StatusCode(), - "body", string(resp.Body)) - return fmt.Errorf("%w: %w (status code %d)", ErrArchiveWallet, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrArchiveWallet, "archiving wallet", resp.Body, c.logger) } } diff --git a/watchers/watchers.go b/watchers/watchers.go index 938420e..25a5d76 100644 --- a/watchers/watchers.go +++ b/watchers/watchers.go @@ -275,22 +275,8 @@ func (c *Client) CreateWithService( "channel_id", channelID.String(), "code", apierror.ConflictCode(resp.JSON409)) return nil, apierror.WrapConflict(resp.JSON409, ErrCreateWatcherService, "channel ID "+channelID.String()) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to create watcher with service - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrCreateWatcherService, resp.StatusCode()) default: - c.logger.Error( - "Failed to create watcher with service - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf( - "%w: %w (status code %d)", ErrCreateWatcherService, apierror.ErrUnexpectedStatusCode, resp.StatusCode(), - ) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateWatcherService, "creating watcher with service", resp.Body, c.logger) } } @@ -410,22 +396,8 @@ func (c *Client) CreateWithABI(ctx context.Context, channelID uuid.UUID, input C "channel_id", channelID.String(), "code", apierror.ConflictCode(resp.JSON409)) return nil, apierror.WrapConflict(resp.JSON409, ErrCreateWatcherABI, "channel ID "+channelID.String()) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to create watcher with ABI - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrCreateWatcherABI, resp.StatusCode()) default: - c.logger.Error( - "Failed to create watcher with ABI - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf( - "%w: %w (status code %d)", ErrCreateWatcherABI, apierror.ErrUnexpectedStatusCode, resp.StatusCode(), - ) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrCreateWatcherABI, "creating watcher with ABI", resp.Body, c.logger) } } @@ -475,20 +447,8 @@ func (c *Client) List(ctx context.Context, channelID uuid.UUID, filters ListFilt return nil, apierror.WrapChannelNotFound( resp.JSON404, ErrListWatchers, "channel ID "+channelID.String(), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to list watchers - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrListWatchers, resp.StatusCode()) default: - c.logger.Error( - "Failed to list watchers - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrListWatchers, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrListWatchers, "listing watchers", resp.Body, c.logger) } } @@ -535,20 +495,8 @@ func (c *Client) Get(ctx context.Context, channelID uuid.UUID, watcherID uuid.UU ErrGetWatcher, fmt.Sprintf("channel ID %s, watcher ID %s", channelID.String(), watcherID.String()), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to get watcher - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrGetWatcher, resp.StatusCode()) default: - c.logger.Error( - "Failed to get watcher - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrGetWatcher, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrGetWatcher, "getting watcher", resp.Body, c.logger) } } @@ -616,20 +564,8 @@ func (c *Client) Update( ErrUpdateWatcher, fmt.Sprintf("channel ID %s, watcher ID %s", channelID.String(), watcherID.String()), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to update watcher - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrUpdateWatcher, resp.StatusCode()) default: - c.logger.Error( - "Failed to update watcher - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrUpdateWatcher, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrUpdateWatcher, "updating watcher", resp.Body, c.logger) } } @@ -787,20 +723,8 @@ func (c *Client) Archive(ctx context.Context, channelID uuid.UUID, watcherID uui ErrArchiveWatcher, fmt.Sprintf("channel ID %s, watcher ID %s", channelID.String(), watcherID.String()), ) - case http.StatusUnauthorized: - c.logger.Error( - "Failed to archive watcher - unauthorized", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, apierror.Wrap(resp.JSON401, ErrArchiveWatcher, resp.StatusCode()) default: - c.logger.Error( - "Failed to archive watcher - unexpected status code", - "status_code", resp.StatusCode(), - "body", string(resp.Body), - ) - return nil, fmt.Errorf("%w: %w (status code %d)", ErrArchiveWatcher, apierror.ErrUnexpectedStatusCode, resp.StatusCode()) + return nil, apierror.HandleErrorStatus(resp.StatusCode(), resp.JSON401, resp.JSON403, ErrArchiveWatcher, "archiving watcher", resp.Body, c.logger) } }