Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 115 additions & 18 deletions errorutils/errorutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,122 @@ package errorutils

import (
"net/http"
)

// ErrorCode represents the platform-wide error codes that can be raised by
// Admin SDK APIs.
type ErrorCode string

const (
// InvalidArgument is a OnePlatform error code.
InvalidArgument ErrorCode = "INVALID_ARGUMENT"

// FailedPrecondition is a OnePlatform error code.
FailedPrecondition ErrorCode = "FAILED_PRECONDITION"

// OutOfRange is a OnePlatform error code.
OutOfRange ErrorCode = "OUT_OF_RANGE"

// Unauthenticated is a OnePlatform error code.
Unauthenticated ErrorCode = "UNAUTHENTICATED"

// PermissionDenied is a OnePlatform error code.
PermissionDenied ErrorCode = "PERMISSION_DENIED"

// NotFound is a OnePlatform error code.
NotFound ErrorCode = "NOT_FOUND"

// Conflict is a custom error code that represents HTTP 409 responses.
//
// OnePlatform APIs typically respond with ABORTED or ALREADY_EXISTS explicitly. But a few
// old APIs send HTTP 409 Conflict without any additional details to distinguish between the two
// cases. For these we currently use this error code. As more APIs adopt OnePlatform conventions
// this will become less important.
Conflict ErrorCode = "CONFLICT"

// Aborted is a OnePlatform error code.
Aborted ErrorCode = "ABORTED"

// AlreadyExists is a OnePlatform error code.
AlreadyExists ErrorCode = "ALREADY_EXISTS"

// ResourceExhausted is a OnePlatform error code.
ResourceExhausted ErrorCode = "RESOURCE_EXHAUSTED"

// Cancelled is a OnePlatform error code.
Cancelled ErrorCode = "CANCELLED"

// DataLoss is a OnePlatform error code.
DataLoss ErrorCode = "DATA_LOSS"

// Unknown is a OnePlatform error code.
Unknown ErrorCode = "UNKNOWN"

"firebase.google.com/go/v4/internal"
// Internal is a OnePlatform error code.
Internal ErrorCode = "INTERNAL"

// Unavailable is a OnePlatform error code.
Unavailable ErrorCode = "UNAVAILABLE"

// DeadlineExceeded is a OnePlatform error code.
DeadlineExceeded ErrorCode = "DEADLINE_EXCEEDED"
)

// FirebaseError is an error type containing an:
// - error code string.
// - error message.
// - HTTP response that caused this error, if any.
// - additional metadata about the error.
type FirebaseError struct {
ErrorCode ErrorCode
String string
Response *http.Response
Ext map[string]interface{}
}

// Error implements the error interface.
func (fe *FirebaseError) Error() string {
return fe.String
}
Comment thread
justinattw marked this conversation as resolved.

// Code returns the canonical error code associated with this error.
func (fe *FirebaseError) Code() ErrorCode {
return fe.ErrorCode
}

// HTTPResponse returns the HTTP response that caused this error, if any.
// Returns nil if the error was not caused by an HTTP response.
func (fe *FirebaseError) HTTPResponse() *http.Response {
return fe.Response
}

// Extensions returns additional metadata associated with this error.
// Returns nil if no extensions are available.
func (fe *FirebaseError) Extensions() map[string]interface{} {
return fe.Ext
}

// IsInvalidArgument checks if the given error was due to an invalid client argument.
func IsInvalidArgument(err error) bool {
return internal.HasPlatformErrorCode(err, internal.InvalidArgument)
return HasPlatformErrorCode(err, InvalidArgument)
}

// IsFailedPrecondition checks if the given error was because a request could not be executed
// in the current system state, such as deleting a non-empty directory.
func IsFailedPrecondition(err error) bool {
return internal.HasPlatformErrorCode(err, internal.FailedPrecondition)
return HasPlatformErrorCode(err, FailedPrecondition)
}

// IsOutOfRange checks if the given error due to an invalid range specified by the client.
func IsOutOfRange(err error) bool {
return internal.HasPlatformErrorCode(err, internal.OutOfRange)
return HasPlatformErrorCode(err, OutOfRange)
}

// IsUnauthenticated checks if the given error was caused by an unauthenticated request.
//
// Unauthenticated requests are due to missing, invalid, or expired OAuth token.
func IsUnauthenticated(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unauthenticated)
return HasPlatformErrorCode(err, Unauthenticated)
}

// IsPermissionDenied checks if the given error was due to a client not having suffificient
Comment thread
justinattw marked this conversation as resolved.
Outdated
Expand All @@ -50,14 +141,14 @@ func IsUnauthenticated(err error) bool {
// This can happen because the OAuth token does not have the right scopes, the client doesn't have
// permission, or the API has not been enabled for the client project.
func IsPermissionDenied(err error) bool {
return internal.HasPlatformErrorCode(err, internal.PermissionDenied)
return HasPlatformErrorCode(err, PermissionDenied)
}

// IsNotFound checks if the given error was due to a specified resource being not found.
//
// This may also occur when the request is rejected by undisclosed reasons, such as whitelisting.
func IsNotFound(err error) bool {
return internal.HasPlatformErrorCode(err, internal.NotFound)
return HasPlatformErrorCode(err, NotFound)
}

// IsConflict checks if the given error was due to a concurrency conflict, such as a
Expand All @@ -66,58 +157,58 @@ func IsNotFound(err error) bool {
// This represents an HTTP 409 Conflict status code, without additional information to distinguish
// between ABORTED or ALREADY_EXISTS error conditions.
func IsConflict(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Conflict)
return HasPlatformErrorCode(err, Conflict)
}

// IsAborted checks if the given error was due to a concurrency conflict, such as a
// read-modify-write conflict.
func IsAborted(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Aborted)
return HasPlatformErrorCode(err, Aborted)
}

// IsAlreadyExists checks if the given error was because a resource that a client tried to create
// already exists.
func IsAlreadyExists(err error) bool {
return internal.HasPlatformErrorCode(err, internal.AlreadyExists)
return HasPlatformErrorCode(err, AlreadyExists)
}

// IsResourceExhausted checks if the given error was caused by either running out of a quota or
// reaching a rate limit.
func IsResourceExhausted(err error) bool {
return internal.HasPlatformErrorCode(err, internal.ResourceExhausted)
return HasPlatformErrorCode(err, ResourceExhausted)
}

// IsCancelled checks if the given error was due to the client cancelling a request.
func IsCancelled(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Cancelled)
return HasPlatformErrorCode(err, Cancelled)
}

// IsDataLoss checks if the given error was due to an unrecoverable data loss or corruption.
//
// The client should report such errors to the end user.
func IsDataLoss(err error) bool {
return internal.HasPlatformErrorCode(err, internal.DataLoss)
return HasPlatformErrorCode(err, DataLoss)
}

// IsUnknown checks if the given error was cuased by an unknown server error.
Comment thread
justinattw marked this conversation as resolved.
Outdated
//
// This typically indicates a server bug.
func IsUnknown(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unknown)
return HasPlatformErrorCode(err, Unknown)
}

// IsInternal checks if the given error was due to an internal server error.
//
// This typically indicates a server bug.
func IsInternal(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Internal)
return HasPlatformErrorCode(err, Internal)
}

// IsUnavailable checks if the given error was caused by an unavailable service.
//
// This typically indicates that the target service is temporarily down.
func IsUnavailable(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unavailable)
return HasPlatformErrorCode(err, Unavailable)
}

// IsDeadlineExceeded checks if the given error was due a request exceeding a deadline.
Expand All @@ -126,7 +217,7 @@ func IsUnavailable(err error) bool {
// deadline (i.e. requested deadline is not enough for the server to process the request) and the
// request did not finish within the deadline.
func IsDeadlineExceeded(err error) bool {
return internal.HasPlatformErrorCode(err, internal.DeadlineExceeded)
return HasPlatformErrorCode(err, DeadlineExceeded)
}

// HTTPResponse returns the http.Response instance that caused the given error.
Expand All @@ -136,10 +227,16 @@ func IsDeadlineExceeded(err error) bool {
// Returns a buffered copy of the original response received from the network stack. It is safe to
// read the response content from the returned http.Response.
func HTTPResponse(err error) *http.Response {
fe, ok := err.(*internal.FirebaseError)
fe, ok := err.(*FirebaseError)
if ok {
return fe.Response
}

return nil
}

// HasPlatformErrorCode checks if the given error contains a specific error code.
func HasPlatformErrorCode(err error, code ErrorCode) bool {
fe, ok := err.(*FirebaseError)
return ok && fe.ErrorCode == code
}
Comment thread
justinattw marked this conversation as resolved.
Loading