Description
Errdetail allows to aggregate information about several errors into one type that implements the error interface.
Errdetail alternatives and similar packages
Based on the "Validation" category.
Alternatively, view errdetail alternatives based on common mentions on social networks and blogs.
-
validator
:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving -
ozzo-validation
An idiomatic Go (golang) validation package. Supports configurable and extensible validation rules (validators) using normal language constructs instead of error-prone struct tags. -
Validate
⚔ Go package for data validation and filtering. support Map, Struct, Form data. Go通用的数据验证与过滤库,使用简单,内置大部分常用验证、过滤器,支持自定义验证器、自定义消息、字段翻译。
SaaSHub - Software Alternatives and Reviews
Do you think we are missing an alternative of Errdetail or a related project?
README
Errdetail Enrich Go errors by context information.
Description
Errdetail allows to add one or multiple details to an error
. Each detail may contain the next optional fields:
Field | Possible usage | Example |
---|---|---|
domain | a particular interest, activity, or type of knowledge | user.management |
code | a unique code for a particular type of error | validation_email_invalid_character |
description | a short, human-readable summary of the problem that should change from occurrence to occurrence of the problem | email address must follow the format described in the RFC 5322 |
field | a field where the error occurred, common for validation issues | user.email |
reason | a human-readable explanation specific to this occurrence of the problem | an invalid character has been detected in the provided sequence |
With such approach it's possible to aggregate information about several errors into one type that implements the error
interface.
Usage
Create a detailed error
err := errdetail.New(
"bad request",
errdetail.NewDetail(
errdetail.WithDomain("user.auth"),
errdetail.WithCode("invalid_email"),
errdetail.WithDescription("email validation failed"),
errdetail.WithField("user.email"),
errdetail.WithReason("invalid character detected: \"#\""),
)
)
Wrap existing error
err := errdetail.Wrap(
errdetail.ErrInvalidArgument,
"bad request",
errdetail.NewDetail(
errdetail.WithDomain("user.auth"),
errdetail.WithCode("invalid_email"),
errdetail.WithDescription("email validation failed"),
errdetail.WithField("user.email"),
errdetail.WithReason("invalid character detected: \"#\""),
),
errdetail.NewDetail(
errdetail.WithDomain("user.auth"),
errdetail.WithCode("invalid_password"),
errdetail.WithDescription("password validation failed"),
errdetail.WithField("user.password"),
errdetail.WithReason("password is empty"),
),
)
Use provided error constructors
err := NewNotFound("discount not found", errdetail.NewDetail(errdetail.WithCode("order_discount_not_supported")))
Use predefined errors
func (a *Adapter) Get(ctx context.Context, id uuid.UUID) (Item, error) {
if item, ok := a.storage.Get(ctx, id); !ok {
return Item{}, errdetail.ErrNotFound
}
// ...
}
Transform errors details to a suitable presentation
type ErrorResponse struct {
Error *Error `json:"error,omitempty"`
}
type Error struct {
Status int `json:"status"`
Title string `json:"title"`
Code ResponseCode `json:"code"`
Details []ErrorDetail `json:"details,omitempty"`
}
type ErrorDetail struct {
Domain string `json:"domain,omitempty"`
Reason string `json:"reason,omitempty"`
Field string `json:"field,omitempty"`
Description string `json:"description,omitempty"`
Code string `json:"code,omitempty"`
}
func NewErrorResponse(err error) ErrorResponse {
if err == nil {
return ErrorResponse{}
}
var (
status int
title string
code ResponseCode
)
switch {
case errors.Is(err, errdetail.ErrInvalidArgument):
status = http.StatusBadRequest
title = errdetail.ErrInvalidArgument.Error()
code = "INVALID_ARGUMENT"
case errors.Is(err, errdetail.ErrNotFound):
status = http.StatusNotFound
title = errdetail.ErrNotFound.Error()
code = "NOT_FOUND"
// ...
default:
status = http.StatusInternalServerError
title = "unknown"
code = "UNKNOWN"
}
return ErrorResponse{
Error: &Error{
Code: code,
Title: title,
Status: status,
Details: extractDetails(err),
},
}
}
func extractDetails(err error) []ErrorDetail {
extracted := errdetail.ExtractDetails(err)
if len(extracted) == 0 {
return nil
}
details := make([]ErrorDetail, len(extracted))
for i := range extracted {
details[i] = ErrorDetail{
Domain: extracted[i].Domain(),
Reason: extracted[i].Reason(),
Field: extracted[i].Field(),
Description: extracted[i].Description(),
Code: extracted[i].Code(),
}
}
return details
}
ErrorResponse
encoded to JSON:
{
"error": {
"status": 400,
"title": "invalid argument",
"code": "INVALID_ARGUMENT",
"details": [
{
"domain": "user.auth",
"code": "invalid_email",
"description": "email validation failed",
"field": "user.email",
"reason": "invalid character detected: \"#\""
},
{
"domain": "user.auth",
"code": "invalid_password",
"description": "password validation failed",
"field": "user.password",
"reason": "password is empty"
}
]
}
}
For further details see examples and reference.
Contributing
For contribution guidelines check CONTRIBUTING.md
*Note that all licence references and agreements mentioned in the Errdetail README section above
are relevant to that project's source code only.