119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
|
package errors
|
|||
|
|
|||
|
import (
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
)
|
|||
|
|
|||
|
// ErrorType представляет тип ошибки
|
|||
|
type ErrorType string
|
|||
|
|
|||
|
const (
|
|||
|
ErrorTypeInvalid ErrorType = "INVALID"
|
|||
|
ErrorTypeNotFound ErrorType = "NOT_FOUND"
|
|||
|
ErrorTypeConflict ErrorType = "CONFLICT"
|
|||
|
ErrorTypeInternal ErrorType = "INTERNAL"
|
|||
|
ErrorTypeUnauthorized ErrorType = "UNAUTHORIZED"
|
|||
|
ErrorTypeForbidden ErrorType = "FORBIDDEN"
|
|||
|
)
|
|||
|
|
|||
|
// AppError - кастомная ошибка приложения
|
|||
|
type AppError struct {
|
|||
|
Type ErrorType `json:"type"`
|
|||
|
Message string `json:"message"`
|
|||
|
Code int `json:"code,omitempty"`
|
|||
|
Err error `json:"-"`
|
|||
|
}
|
|||
|
|
|||
|
// Error реализует интерфейс error
|
|||
|
func (e *AppError) Error() string {
|
|||
|
if e.Err != nil {
|
|||
|
return fmt.Sprintf("%s: %v", e.Message, e.Err)
|
|||
|
}
|
|||
|
return e.Message
|
|||
|
}
|
|||
|
|
|||
|
// Unwrap для поддержки errors.Unwrap
|
|||
|
func (e *AppError) Unwrap() error {
|
|||
|
return e.Err
|
|||
|
}
|
|||
|
|
|||
|
// WithCode добавляет HTTP код к ошибке
|
|||
|
func (e *AppError) WithCode(code int) *AppError {
|
|||
|
e.Code = code
|
|||
|
return e
|
|||
|
}
|
|||
|
|
|||
|
// Wrap оборачивает существующую ошибку
|
|||
|
func (e *AppError) Wrap(err error) *AppError {
|
|||
|
e.Err = err
|
|||
|
return e
|
|||
|
}
|
|||
|
|
|||
|
// Конструкторы ошибок
|
|||
|
func NewInvalidError(message string) *AppError {
|
|||
|
return &AppError{
|
|||
|
Type: ErrorTypeInvalid,
|
|||
|
Message: message,
|
|||
|
Code: 400,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func NewNotFoundError(message string) *AppError {
|
|||
|
return &AppError{
|
|||
|
Type: ErrorTypeNotFound,
|
|||
|
Message: message,
|
|||
|
Code: 404,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func NewInternalError(message string) *AppError {
|
|||
|
return &AppError{
|
|||
|
Type: ErrorTypeInternal,
|
|||
|
Message: message,
|
|||
|
Code: 500,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func NewConflictError(message string) *AppError {
|
|||
|
return &AppError{
|
|||
|
Type: ErrorTypeConflict,
|
|||
|
Message: message,
|
|||
|
Code: 409,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Вспомогательные функции для проверки типов ошибок
|
|||
|
func IsNotFound(err error) bool {
|
|||
|
var appErr *AppError
|
|||
|
if errors.As(err, &appErr) {
|
|||
|
return appErr.Type == ErrorTypeNotFound
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
func IsInvalid(err error) bool {
|
|||
|
var appErr *AppError
|
|||
|
if errors.As(err, &appErr) {
|
|||
|
return appErr.Type == ErrorTypeInvalid
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
func IsConflict(err error) bool {
|
|||
|
var appErr *AppError
|
|||
|
if errors.As(err, &appErr) {
|
|||
|
return appErr.Type == ErrorTypeConflict
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
// Wrap оборачивает ошибку с сообщением
|
|||
|
func Wrap(err error, message string) error {
|
|||
|
return fmt.Errorf("%s: %w", message, err)
|
|||
|
}
|
|||
|
|
|||
|
func Wrapf(err error, format string, args ...interface{}) error {
|
|||
|
return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
|
|||
|
}
|