Documentation
¶
Index ¶
- Constants
- func AssertFieldViolations(t *testing.T, err error, fvs ...*FieldViolation)
- func Error(httpStatus int, reason, message string) error
- func ErrorMiddleware(conf *HTTPErrorMiddlewareConfig) func(http.Handler) http.Handler
- func Errorf(httpStatus int, reason, format string, a ...any) error
- func FormatField(field string, formatFunc func(string) string) string
- func HandleError(conf *HTTPErrorMiddlewareConfig, w http.ResponseWriter, r *http.Request, ...)
- func NewErrorMiddleware(ib *i18nx.I18N) func(http.Handler) http.Handler
- func Reason(err error) string
- func ReasonFromStatus(httpStatus int) string
- func StatusCode(err error) int
- func TranslateError(err error, ib *i18nx.I18N, lang language.Tag) error
- func TranslateStatusErrorOnly(err error, ib *i18nx.I18N, lang language.Tag) (error, bool)
- func Validate(ctx context.Context, input any) error
- func WrapHandlerFunc(conf *HTTPErrorMiddlewareConfig, handler http.HandlerFunc) http.HandlerFunc
- func WriteError(conf *HTTPErrorMiddlewareConfig, w http.ResponseWriter, r *http.Request, ...) error
- func WriteJSONError(err error, w http.ResponseWriter) error
- type ContextValidator
- type ErrorResponse
- type ErrorResponseFieldViolation
- type FieldViolation
- func (f *FieldViolation) Clone() *FieldViolation
- func (f *FieldViolation) Description() string
- func (f *FieldViolation) Field() string
- func (f *FieldViolation) GetLocalized() *Localized
- func (f *FieldViolation) GetLocalizedMessage() *LocalizedMessage
- func (f *FieldViolation) Reason() string
- func (f *FieldViolation) WithLocalized(key string, args ...any) *FieldViolation
- func (f *FieldViolation) WithLocalizedArgs(args ...any) *FieldViolation
- type FieldViolations
- type HTTPErrorMiddlewareConfig
- type HTTPWriteErrorFunc
- type HTTPWriteErrorInput
- type HTTPWriteErrorOutput
- type Localized
- type LocalizedMessage
- type Status
- func BadRequest(inputs ...any) *Status
- func Clone(s *Status) *Status
- func Convert(err error) *Status
- func FromError(err error) (s *Status, ok bool)
- func New(httpStatus int, reason, message string) *Status
- func NewStatus(httpStatus int, message string) *Status
- func NewStatusf(httpStatus int, format string, a ...any) *Status
- func Newf(httpStatus int, reason, format string, a ...any) *Status
- func Wrap(err error, httpStatus int, reason, message string) *Status
- func WrapStatus(err error, httpStatus int, message string) *Status
- func WrapStatusf(err error, httpStatus int, format string, a ...any) *Status
- func Wrapf(err error, httpStatus int, reason, format string, a ...any) *Status
- func (s *Status) Cause() error
- func (s *Status) Err() error
- func (s *Status) FieldViolations() []*FieldViolation
- func (s *Status) GetLocalizedMessage() *LocalizedMessage
- func (s *Status) Localized() *Localized
- func (s *Status) Message() string
- func (s *Status) Metadata() map[string]string
- func (s *Status) Reason() string
- func (s *Status) StatusCode() int
- func (s *Status) String() string
- func (s *Status) ToFieldViolations(field string) FieldViolations
- func (s *Status) Translated(ib *i18nx.I18N, lang language.Tag) *Status
- func (s *Status) WithCause(cause error) *Status
- func (s *Status) WithFieldViolations(fieldViolations ...*FieldViolation) *Status
- func (s *Status) WithFlattenFieldViolations(inputs ...any) *Status
- func (s *Status) WithLocalized(key string, args ...any) *Status
- func (s *Status) WithLocalizedArgs(args ...any) *Status
- func (s *Status) WithMessage(message string) *Status
- func (s *Status) WithMessagef(format string, a ...any) *Status
- func (s *Status) WithMetadata(md map[string]string) *Status
- func (s *Status) WithReason(reason string) *Status
- func (s *Status) WithStatusCode(httpStatus int) *Status
- type StatusError
- type Validator
Constants ¶
const ( ReasonOK = "OK" ReasonCanceled = "CANCELED" ReasonUnknown = "UNKNOWN" ReasonInvalidArgument = "INVALID_ARGUMENT" ReasonDeadlineExceeded = "DEADLINE_EXCEEDED" ReasonNotFound = "NOT_FOUND" ReasonAlreadyExists = "ALREADY_EXISTS" ReasonPermissionDenied = "PERMISSION_DENIED" ReasonResourceExhausted = "RESOURCE_EXHAUSTED" ReasonFailedPrecondition = "FAILED_PRECONDITION" ReasonAborted = "ABORTED" ReasonOutOfRange = "OUT_OF_RANGE" ReasonUnimplemented = "UNIMPLEMENTED" ReasonInternal = "INTERNAL" ReasonDataLoss = "DATA_LOSS" ReasonUnauthenticated = "UNAUTHENTICATED" )
Common reason constants for HTTP errors. These replace the protobuf ErrorReason enum from statusx.
Variables ¶
This section is empty.
Functions ¶
func AssertFieldViolations ¶
func AssertFieldViolations(t *testing.T, err error, fvs ...*FieldViolation)
func ErrorMiddleware ¶
func ErrorMiddleware(conf *HTTPErrorMiddlewareConfig) func(http.Handler) http.Handler
ErrorMiddleware creates an HTTP middleware that: 1. Injects i18n context into the request 2. Recovers from panics containing errors 3. Translates and writes structured JSON error responses
Currently uses panic-based error propagation to keep handler signatures as standard http.HandlerFunc. NOTE: In the future, this may be changed to support a handler signature that returns error directly (e.g., type HandlerFunc func(w http.ResponseWriter, r *http.Request) error). The panic-based approach is chosen for now to maintain compatibility with standard http.HandlerFunc.
func FormatField ¶
FormatField formats a dotted field path by applying a formatting function to each segment while preserving array index notations (e.g., [0], [1]).
Parameters:
- field: The original field path (e.g., "user_info.addresses[0].street_name")
- formatFunc: Function to apply to each field segment (e.g., lo.CamelCase)
Returns:
- The formatted field path with proper array index preservation
Example:
FormatField("user_info.addresses[0].street_name", lo.CamelCase)
Returns: "userInfo.addresses[0].streetName"
func HandleError ¶
func HandleError(conf *HTTPErrorMiddlewareConfig, w http.ResponseWriter, r *http.Request, err error)
HandleError translates and writes a structured JSON error response for the given error. It is kept for backward compatibility and intentionally does not return write errors.
func NewErrorMiddleware ¶
NewErrorMiddleware is a convenience function that creates an ErrorMiddleware with default configuration.
func ReasonFromStatus ¶
ReasonFromStatus returns a default reason string for a given HTTP status code.
func StatusCode ¶
func TranslateError ¶
TranslateError translates error messages and field violations using the provided i18n instance and language. It always returns an error derived from a status representation of the input error (typically a *StatusError);
Translation behavior:
- The original message is preserved in the `message` field.
- The translated text is stored in the `localizedMessage` field.
- If the Localized template is set, its key and args are used for translation.
- Otherwise, the error reason is used as the i18n key fallback.
- If already translated (localized is nil), translation is skipped.
func TranslateStatusErrorOnly ¶
TranslateStatusErrorOnly translates only StatusError types, returning the error and a boolean indicating success
func WrapHandlerFunc ¶
func WrapHandlerFunc(conf *HTTPErrorMiddlewareConfig, handler http.HandlerFunc) http.HandlerFunc
WrapHandlerFunc wraps a single http.HandlerFunc with httperrors panic recovery and i18n translation. This is useful when only some handlers in a mux use httperrors, and a global middleware is not appropriate.
Usage:
mux.HandleFunc("/api/users/{id}", httperrors.WrapHandlerFunc(conf, h.GetUser))
mux.HandleFunc("/legacy/other", legacyHandler) // not wrapped
func WriteError ¶
func WriteError(conf *HTTPErrorMiddlewareConfig, w http.ResponseWriter, r *http.Request, err error) error
WriteError translates and writes a structured JSON error response for the given error. This is intended for use inside individual handlers that want to explicitly handle errors without relying on panic-based middleware.
Usage:
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
user, err := h.userService.GetUser(r.Context(), r.PathValue("id"))
if err != nil {
if herr := httperrors.WriteError(h.conf, w, r, err); herr != nil {
slog.ErrorContext(r.Context(), "Failed to write http response error", "error", err, "writeError", herr)
}
return
}
json.NewEncoder(w).Encode(user)
}
func WriteJSONError ¶
func WriteJSONError(err error, w http.ResponseWriter) error
WriteJSONError writes a structured JSON error response from an error. The HTTP status code is set from the Status object. The response body follows the ErrorResponse format with camelCase fields.
Types ¶
type ContextValidator ¶
type ErrorResponse ¶
type ErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
LocalizedMessage string `json:"localizedMessage,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
FieldViolations []*ErrorResponseFieldViolation `json:"fieldViolations,omitempty"`
}
ErrorResponse is the standard JSON error response body. Fields use camelCase for frontend compatibility.
type ErrorResponseFieldViolation ¶
type ErrorResponseFieldViolation struct {
Field string `json:"field"`
Code string `json:"code"`
Message string `json:"message"`
LocalizedMessage string `json:"localizedMessage,omitempty"`
}
ErrorResponseFieldViolation represents a single field violation in the JSON error response.
type FieldViolation ¶
type FieldViolation struct {
// contains filtered or unexported fields
}
FieldViolation represents a field-level validation violation with localization capability.
Translation preserves the original description and stores the translated text in localizedMessage. Priority order for localized messages:
- LocalizedMessage (highest priority - pre-translated, ready to use)
- Localized (lower priority - template that needs translation via middleware)
func NewFieldViolation ¶
func NewFieldViolation(field, reason, description string) *FieldViolation
NewFieldViolation creates a new field validation violation. The reason serves as the error identifier and will be used as the i18n key fallback during translation.
func NewFieldViolationf ¶
func NewFieldViolationf(field, reason, format string, args ...any) *FieldViolation
NewFieldViolationf creates a new field validation violation with a formatted description.
func (*FieldViolation) Clone ¶
func (f *FieldViolation) Clone() *FieldViolation
Clone creates a deep copy of this FieldViolation.
func (*FieldViolation) Description ¶
func (f *FieldViolation) Description() string
Description returns the human-readable description of the violation.
func (*FieldViolation) Field ¶
func (f *FieldViolation) Field() string
Field returns the field name that caused the violation.
func (*FieldViolation) GetLocalized ¶
func (f *FieldViolation) GetLocalized() *Localized
GetLocalized returns the localization template if set. Returns nil if no localization template is available.
func (*FieldViolation) GetLocalizedMessage ¶
func (f *FieldViolation) GetLocalizedMessage() *LocalizedMessage
GetLocalizedMessage returns the pre-translated message if available. Returns nil if no pre-translated message is set.
func (*FieldViolation) Reason ¶
func (f *FieldViolation) Reason() string
Reason returns the error reason code.
func (*FieldViolation) WithLocalized ¶
func (f *FieldViolation) WithLocalized(key string, args ...any) *FieldViolation
WithLocalized sets a custom i18n key and template arguments. This sets a specific i18n key instead of relying on the reason as fallback during translation.
func (*FieldViolation) WithLocalizedArgs ¶
func (f *FieldViolation) WithLocalizedArgs(args ...any) *FieldViolation
WithLocalizedArgs sets template arguments for i18n. This method relies on the constructor invariant that localized is initialized with the reason as the default key. Use WithLocalized if you need to change the translation key before setting args.
type FieldViolations ¶
type FieldViolations []*FieldViolation
func FlattenFieldViolations ¶
func FlattenFieldViolations(inputs ...any) (FieldViolations, error)
FlattenFieldViolations flattens various field violation types into a unified FieldViolations slice. Supports *FieldViolation, []*FieldViolation, FieldViolations. Mixed types are allowed in a single call.
Note: For error and *Status inputs, use ToFieldViolations(err, field) or status.ToFieldViolations(field) first to specify the field name, then pass the result to this function.
func PrependField ¶
func PrependField(field string, fvs ...*FieldViolation) FieldViolations
PrependField prepends a field name to the field name of each field violation.
func ToFieldViolations ¶
func ToFieldViolations(err error, field string) FieldViolations
ToFieldViolations converts any error to field violations for the specified field. Simple behavior:
- If field is empty: returns only nested field violations without prefix
- If field is non-empty: returns only nested field violations with the specified field prefix
This design extracts meaningful field-level violations from container errors.
func (FieldViolations) PrependField ¶
func (fvs FieldViolations) PrependField(field string) FieldViolations
type HTTPErrorMiddlewareConfig ¶
type HTTPErrorMiddlewareConfig struct {
I18N *i18nx.I18N
// contains filtered or unexported fields
}
func (*HTTPErrorMiddlewareConfig) WithHTTPWriteErrorHook ¶
func (c *HTTPErrorMiddlewareConfig) WithHTTPWriteErrorHook(hooks ...hook.Hook[HTTPWriteErrorFunc]) *HTTPErrorMiddlewareConfig
type HTTPWriteErrorFunc ¶
type HTTPWriteErrorFunc func(ctx context.Context, input *HTTPWriteErrorInput) (*HTTPWriteErrorOutput, error)
type HTTPWriteErrorInput ¶
type HTTPWriteErrorInput struct {
Conf *HTTPErrorMiddlewareConfig
W http.ResponseWriter
R *http.Request
Err error
}
type HTTPWriteErrorOutput ¶
type HTTPWriteErrorOutput struct {
Written bool
}
type Localized ¶
type Localized struct {
// contains filtered or unexported fields
}
Localized represents a localization template with a key and optional arguments.
type LocalizedMessage ¶
LocalizedMessage represents a pre-translated message with its locale.
func (*LocalizedMessage) Clone ¶
func (lm *LocalizedMessage) Clone() *LocalizedMessage
type Status ¶
type Status struct {
// contains filtered or unexported fields
}
func BadRequest ¶
BadRequest creates a new Status with http.StatusBadRequest (400) and a flattened list of field violations.
func New ¶
New creates a Status with the specified HTTP status code, reason, and message.
For non-2xx status codes, it automatically captures a stacktrace at creation time, which provides valuable debugging context without manual instrumentation.
Parameters:
- httpStatus: The HTTP status code (e.g., 400, 404, 500)
- reason: A string identifier used as the error reason and i18n key fallback during translation
- message: A human-readable message for debugging purposes
The reason serves as both the error identifier and the i18n key. The reason is immediately fixed as the i18n key at creation time. Use WithLocalized() to override with a specific i18n key and args if needed. Use WithLocalizedArgs() to add template arguments while preserving the current key. Returns a Status object that can be further enriched with metadata or localization.
func NewStatus ¶
NewStatus creates a Status with automatically derived reason from the HTTP status code. This is a convenience function that uses ReasonFromStatus to generate the reason.
func NewStatusf ¶
NewStatusf creates a Status with automatically derived reason and formatted message.
func WrapStatus ¶
WrapStatus wraps an error with automatically derived reason from the HTTP status code.
func WrapStatusf ¶
WrapStatusf wraps an error with automatically derived reason and formatted message.
func (*Status) Err ¶
Err converts the Status to an error interface.
The returned error type is either:
- nil: When StatusCode() is 2xx
- *StatusError: An error that implements the error interface
func (*Status) FieldViolations ¶
func (s *Status) FieldViolations() []*FieldViolation
func (*Status) GetLocalizedMessage ¶
func (s *Status) GetLocalizedMessage() *LocalizedMessage
func (*Status) StatusCode ¶
func (*Status) ToFieldViolations ¶
func (s *Status) ToFieldViolations(field string) FieldViolations
ToFieldViolations converts this Status to field violations for the specified field
func (*Status) Translated ¶
Translated returns a new Status with translated messages stored in localizedMessage fields. The original message is preserved unchanged.
func (*Status) WithFieldViolations ¶
func (s *Status) WithFieldViolations(fieldViolations ...*FieldViolation) *Status
WithFieldViolations adds multiple field-level validation violations in batch. Multiple violations for the same field are allowed and will be appended.
func (*Status) WithFlattenFieldViolations ¶
WithFlattenFieldViolations accepts various types of field violation inputs and flattens them. Supports *FieldViolation, []*FieldViolation, FieldViolations. Mixed types are allowed in a single call for maximum flexibility.
Note: For error and *Status inputs, use ToFieldViolations(err, field) or status.ToFieldViolations(field) first to specify the field name, then pass the result to this function.
func (*Status) WithLocalizedArgs ¶
WithLocalizedArgs sets template arguments for i18n. This method relies on the constructor invariant that localized is initialized with the reason as the default key. Use WithLocalized if you need to change the translation key before setting args.
func (*Status) WithMessage ¶
func (*Status) WithReason ¶
func (*Status) WithStatusCode ¶
type StatusError ¶
type StatusError struct {
// contains filtered or unexported fields
}
func (*StatusError) Cause ¶
func (e *StatusError) Cause() error
func (*StatusError) Error ¶
func (e *StatusError) Error() string
func (*StatusError) Is ¶
func (e *StatusError) Is(target error) bool
Is compares two StatusErrors by httpStatus + reason (decision: scheme A).
func (*StatusError) Status ¶
func (e *StatusError) Status() *Status
func (*StatusError) Unwrap ¶
func (e *StatusError) Unwrap() error