package domain import ( "errors" "fmt" "net/http" ) var ( ErrUnauthorized = errors.New("unauthorized") ErrForbidden = errors.New("forbidden") ErrNotFound = errors.New("not found") ErrBadRequest = errors.New("bad request") ErrInternalServer = errors.New("internal server error") ErrConflict = errors.New("conflict") ErrInvalidToken = errors.New("invalid token") ErrMissingAuthHeader = errors.New("missing authorization header") ErrInvalidFile = errors.New("invalid file") ErrFileTooLarge = errors.New("file too large") ) type AppError struct { Err error Message string StatusCode int } func (e *AppError) Error() string { if e.Message != "" { return e.Message } if e.Err != nil { return e.Err.Error() } return "unknown error" } func NewAppError(err error, message string, statusCode int) *AppError { return &AppError{ Err: err, Message: message, StatusCode: statusCode, } } func NewBadRequestError(message string) *AppError { return &AppError{ Err: ErrBadRequest, Message: message, StatusCode: http.StatusBadRequest, } } func NewUnauthorizedError(message string) *AppError { return &AppError{ Err: ErrUnauthorized, Message: message, StatusCode: http.StatusUnauthorized, } } func NewForbiddenError(message string) *AppError { return &AppError{ Err: ErrForbidden, Message: message, StatusCode: http.StatusForbidden, } } func NewNotFoundError(message string) *AppError { return &AppError{ Err: ErrNotFound, Message: message, StatusCode: http.StatusNotFound, } } func NewConflictError(message string) *AppError { return &AppError{ Err: ErrConflict, Message: message, StatusCode: http.StatusConflict, } } func NewInternalServerError(message string) *AppError { return &AppError{ Err: ErrInternalServer, Message: message, StatusCode: http.StatusInternalServerError, } } type ErrorResponse struct { Error string `json:"error"` Message string `json:"message,omitempty"` Details string `json:"details,omitempty"` } func NewErrorResponse(err error, message string) *ErrorResponse { errMsg := "internal server error" if err != nil { errMsg = err.Error() } return &ErrorResponse{ Error: errMsg, Message: message, } } func GRPCErrorToHTTPStatus(err error) int { if err == nil { return http.StatusOK } errMsg := err.Error() switch { case contains(errMsg, "not found"): return http.StatusNotFound case contains(errMsg, "already exists"), contains(errMsg, "conflict"): return http.StatusConflict case contains(errMsg, "invalid"), contains(errMsg, "bad request"): return http.StatusBadRequest case contains(errMsg, "unauthorized"), contains(errMsg, "unauthenticated"): return http.StatusUnauthorized case contains(errMsg, "forbidden"), contains(errMsg, "permission denied"): return http.StatusForbidden default: return http.StatusInternalServerError } } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || fmt.Sprintf("%s", s) != s) }