46 lines
1.3 KiB
Go
46 lines
1.3 KiB
Go
package errors
|
|
|
|
import (
|
|
stdErrors "errors"
|
|
"net/http"
|
|
)
|
|
|
|
// HTTPStatus resolves the HTTP status code for err.
|
|
//
|
|
// If err (or anything wrapped by it) is an AppError with a non-zero HTTPCode,
|
|
// that code is returned; otherwise the fallback is http.StatusInternalServerError
|
|
// (500). New and Wrap propagate the cause's status, so wrapping a sentinel such
|
|
// as ErrNotFound keeps status 404.
|
|
func HTTPStatus(err error) int {
|
|
var appErr *AppError
|
|
if stdErrors.As(err, &appErr) && appErr.HTTPCode != 0 {
|
|
return appErr.HTTPCode
|
|
}
|
|
return http.StatusInternalServerError
|
|
}
|
|
|
|
// ToJSON renders err as an RFC 7807 style error object, aligned with the client
|
|
// API contract {error:{code,message}}.
|
|
//
|
|
// For an AppError (or one wrapped by it) the Code and Message are returned
|
|
// verbatim. For any other error a generic internal error is returned so that
|
|
// internal details are never leaked to the user; the underlying error is kept
|
|
// only in the Cause field for logging.
|
|
func ToJSON(err error) map[string]any {
|
|
var appErr *AppError
|
|
if stdErrors.As(err, &appErr) {
|
|
return map[string]any{
|
|
"error": map[string]any{
|
|
"code": appErr.Code,
|
|
"message": appErr.Message,
|
|
},
|
|
}
|
|
}
|
|
return map[string]any{
|
|
"error": map[string]any{
|
|
"code": ErrInternal.Code,
|
|
"message": ErrInternal.Message,
|
|
},
|
|
}
|
|
}
|