128 lines
2.8 KiB
Go
128 lines
2.8 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"
|
||
ErrorTypeNetwork ErrorType = "NETWORK"
|
||
)
|
||
|
||
// 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 NewNetworkError(message string) *AppError {
|
||
return &AppError{
|
||
Type: ErrorTypeNetwork,
|
||
Message: message,
|
||
Code: 0, // Network errors don't have HTTP codes
|
||
}
|
||
}
|
||
|
||
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)
|
||
}
|