feat(xerrors): initial stable release v0.9.0
Structured application errors with typed codes, cause chaining, key-value context fields, and zero-import logz enrichment bridge. What's included: - `*Err` type implementing error, errors.Unwrap, json.Marshaler, ErrorCode(), and ErrorContext() - Twelve typed Code constants aligned with gRPC canonical status names - New / Wrap factory constructors plus InvalidInput / NotFound / Internal convenience constructors - Builder methods WithContext and WithError for attaching structured fields and causes - Duck-typed ErrorCode() / ErrorContext() bridge so logz auto-enriches log records without an import Tested-via: todo-api POC integration Reviewed-against: docs/adr/
This commit is contained in:
97
code.go
Normal file
97
code.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package xerrors
|
||||
|
||||
// Code is the machine-readable error category.
|
||||
// Wire values are stable across versions and are identical to gRPC status code names.
|
||||
// HTTP mapping is the responsibility of the transport layer, not this package.
|
||||
type Code string
|
||||
|
||||
const (
|
||||
// ErrInvalidInput indicates the request contains malformed or invalid data.
|
||||
// The caller should fix the input before retrying.
|
||||
ErrInvalidInput Code = "INVALID_ARGUMENT"
|
||||
|
||||
// ErrUnauthorized indicates the request lacks valid authentication credentials.
|
||||
// The caller should authenticate and retry.
|
||||
ErrUnauthorized Code = "UNAUTHENTICATED"
|
||||
|
||||
// ErrPermissionDenied indicates the authenticated caller lacks permission for the operation.
|
||||
// Authentication is not the issue — the caller is authenticated but not authorised.
|
||||
ErrPermissionDenied Code = "PERMISSION_DENIED"
|
||||
|
||||
// ErrNotFound indicates the requested resource does not exist.
|
||||
ErrNotFound Code = "NOT_FOUND"
|
||||
|
||||
// ErrAlreadyExists indicates a resource with the same identifier already exists.
|
||||
// Use for creation conflicts (e.g. duplicate email on sign-up).
|
||||
// For state-based conflicts not related to creation, use ErrPreconditionFailed.
|
||||
ErrAlreadyExists Code = "ALREADY_EXISTS"
|
||||
|
||||
// ErrGone indicates the resource existed but has been permanently removed.
|
||||
// Unlike ErrNotFound, this signals the caller should not retry — the resource
|
||||
// is gone for good (e.g. a soft-deleted record that has been purged).
|
||||
ErrGone Code = "GONE"
|
||||
|
||||
// ErrPreconditionFailed indicates the operation was rejected because a required
|
||||
// condition was not met. The input is valid but a business rule blocks the action
|
||||
// (e.g. "cannot delete an account with active subscriptions", or an optimistic-lock
|
||||
// mismatch). Different from ErrAlreadyExists (duplicate creation) and
|
||||
// ErrInvalidInput (bad data).
|
||||
ErrPreconditionFailed Code = "FAILED_PRECONDITION"
|
||||
|
||||
// ErrRateLimited indicates the caller has exceeded a rate limit or exhausted a quota.
|
||||
ErrRateLimited Code = "RESOURCE_EXHAUSTED"
|
||||
|
||||
// ErrCancelled indicates the operation was cancelled, typically because the caller
|
||||
// disconnected or the request context was cancelled.
|
||||
// Useful for translating context.Canceled to a structured error at service boundaries.
|
||||
ErrCancelled Code = "CANCELLED"
|
||||
|
||||
// ErrInternal indicates an unexpected server-side failure.
|
||||
// This code should not be used when a more specific code applies.
|
||||
ErrInternal Code = "INTERNAL"
|
||||
|
||||
// ErrNotImplemented indicates the requested operation has not been implemented.
|
||||
ErrNotImplemented Code = "UNIMPLEMENTED"
|
||||
|
||||
// ErrUnavailable indicates the service is temporarily unable to handle requests.
|
||||
// The caller may retry with backoff.
|
||||
ErrUnavailable Code = "UNAVAILABLE"
|
||||
|
||||
// ErrDeadlineExceeded indicates the operation timed out before completing.
|
||||
ErrDeadlineExceeded Code = "DEADLINE_EXCEEDED"
|
||||
)
|
||||
|
||||
// Description returns a human-readable description for the code.
|
||||
// Unknown codes return their raw string value.
|
||||
func (c Code) Description() string {
|
||||
switch c {
|
||||
case ErrInvalidInput:
|
||||
return "Invalid input provided"
|
||||
case ErrUnauthorized:
|
||||
return "Authentication required"
|
||||
case ErrPermissionDenied:
|
||||
return "Insufficient permissions"
|
||||
case ErrNotFound:
|
||||
return "Resource not found"
|
||||
case ErrAlreadyExists:
|
||||
return "Resource already exists"
|
||||
case ErrGone:
|
||||
return "Resource permanently deleted"
|
||||
case ErrPreconditionFailed:
|
||||
return "Precondition not met"
|
||||
case ErrRateLimited:
|
||||
return "Rate limit exceeded"
|
||||
case ErrCancelled:
|
||||
return "Request cancelled"
|
||||
case ErrInternal:
|
||||
return "Internal error"
|
||||
case ErrNotImplemented:
|
||||
return "Not implemented"
|
||||
case ErrUnavailable:
|
||||
return "Service unavailable"
|
||||
case ErrDeadlineExceeded:
|
||||
return "Deadline exceeded"
|
||||
default:
|
||||
return string(c)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user