go-errors

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 15, 2025 License: MIT

README

Go Errors Package

Пакет ошибок Go предоставляет расширенный способ обработки ошибок в микросервисах, полностью совместимый со стандартным пакетом errors из Go 1.13+. Он включает единый тип ошибки с поддержкой HTTP-кодов состояния, JSON-представления и интеграцией с errors.Is/errors.As.

Основные возможности

  • Полная совместимость со стандартным пакетом errors:

    • Поддержка errors.Is и errors.As для проверки и приведения типов ошибок
    • Поддержка errors.Unwrap для цепочек ошибок
    • Взаимодействие со стандартными ошибками Go
  • HTTP-интеграция и API:

    • Единый тип Error с HTTP-кодами состояния и JSON-представлением
    • Предопределенные ошибки для типичных HTTP-сценариев
    • Функции для автоматического форматирования HTTP-ответов
  • Удобное API для работы с ошибками:

    • Методы для кастомизации сообщений и метаданных
    • Функции для оборачивания стандартных ошибок Go
    • Константы HTTP-кодов, совместимые с пакетом net/http
  • Интеграция с веб-фреймворками и логированием:

    • Примеры использования с Fiber через middleware
    • Поддержка стандартного http.Handler
    • Простое логирование цепочек ошибок в консольных приложениях
    • Интеграция с Fiber logger для структурированного логирования

Установка

go get github.com/Vova4o/go-errors

Использование

1. Создание и использование ошибок
import "github.com/Vova4o/go-errors/errors"

// Создание новой ошибки с HTTP-кодом
err := errors.NewError(errors.StatusBadRequest, "Неверный формат JSON", nil)

// Использование предопределенной ошибки
err = errors.ErrNotFound

// Кастомизация сообщения ошибки
err = errors.ErrNotFound.WithMessage("Пользователь с ID 123 не найден")

// Оборачивание стандартной ошибки Go
baseErr := stderrors.New("timeout after 30s")
err = errors.Wrap(baseErr, errors.StatusGatewayTimeout, "Ошибка подключения к БД")
2. Совместимость со стандартным пакетом errors
import (
    stderrors "errors" // стандартный пакет errors
    "go-errors-package/errors" // наш пакет
)

// Проверка типа ошибки через errors.Is
if stderrors.Is(err, errors.ErrNotFound) {
    // Обработка "не найдено"
}

// Мы также предоставляем прокси для стандартных функций
if errors.Is(err, errors.ErrNotFound) {
    // То же самое, что и выше
}

// Извлечение дополнительной информации через errors.As
var customErr errors.Error
if stderrors.As(err, &customErr) {
    log.Printf("HTTP код: %d, сообщение: %s", customErr.Code, customErr.Message)
}

// Работа с цепочкой ошибок
originalErr := stderrors.Unwrap(err)
// Или с помощью нашего прокси
originalErr = errors.Unwrap(err)
3. Обработка HTTP-ответов
func Handler(w http.ResponseWriter, r *http.Request) {
    result, err := processRequest(r)
    if err != nil {
        // Автоматическая обработка любого типа ошибок
        errors.HandleHTTPResponse(w, err)
        return
    }

    // Отправка успешного ответа
    errors.WriteSuccessResponse(w, result)
}
4. Интеграция с Fiber через Middleware
// Middleware для обработки ошибок
func ErrorHandler() fiber.Handler {
    return func(c *fiber.Ctx) error {
        err := c.Next()
        if err == nil {
            return nil
        }

        statusCode := fiber.StatusInternalServerError
        errorResponse := fiber.Map{
            "status":  "ERROR",
            "message": "Internal server error",
        }

        var customErr errors.Error
        if stderrors.As(err, &customErr) {
            statusCode = customErr.Code
            errorResponse["status"] = customErr.Status
            errorResponse["message"] = customErr.Message

            // Логирование с распаковкой цепочки ошибок
            logError(c, customErr)
        } else {
            errorResponse["message"] = err.Error()
        }

        return c.Status(statusCode).JSON(errorResponse)
    }
}

// Использование в приложении
app := fiber.New()
app.Use(ErrorHandler())
app.Get("/users/:id", getUserHandler)
5. Логирование ошибок в консольных приложениях
// Простой логер для консольных приложений
type ErrorLogger struct {
    prefix string
}

// Метод для логирования ошибок с распаковкой цепочки
func (l *ErrorLogger) Log(err error) {
    if err == nil {
        return
    }

    // Вывод основной информации об ошибке
    fmt.Printf("[%s] ERROR: ", l.prefix)

    // Проверяем, является ли ошибка нашей структурированной ошибкой
    var customErr errors.Error
    if stderrors.As(err, &customErr) {
        fmt.Printf("[%d] %s\n", customErr.Code, customErr.Message)

        // Распаковка цепочки ошибок для отладки
        cause := customErr.Unwrap()
        indent := "  "
        for cause != nil {
            fmt.Printf("%s↳ %v\n", indent, cause)
            cause = stderrors.Unwrap(cause) // Используем стандартную функцию Unwrap
            indent += "  "
        }
    } else {
        // Обычная ошибка Go
        fmt.Printf("%v\n", err)
    }
}

// Пример использования
logger := &ErrorLogger{prefix: "APP"}

// Создание цепочки ошибок
baseErr := stderrors.New("timeout error")
dbErr := errors.Wrap(baseErr, errors.StatusServiceUnavailable, "Ошибка БД")
serviceErr := errors.Wrap(dbErr, errors.StatusInternalServerError, "Ошибка сервиса")

// Логирование
logger.Log(serviceErr)
// Выведет:
// [APP] ERROR: [500] Ошибка сервиса
//   ↳ Ошибка БД: timeout error
//     ↳ timeout error
6. Интеграция с Fiber Logger

Если вы предпочитаете использовать структурированное логирование, вы можете легко интегрировать наш пакет ошибок с Fiber Logger:

import (
    stderrors "errors"
    "github.com/gofiber/fiber/v2/log"
    customerrors "gitlab.com/multispek/go-errors-package/errors"
)

// Функция для форматирования цепочки ошибок
func formatErrorChain(err error) string {
    if err == nil {
        return ""
    }

    var customErr customerrors.Error
    if customerrors.As(err, &customErr) {
        // Базовая информация об ошибке
        result := fmt.Sprintf("[%d] %s", customErr.Code, customErr.Message)

        // Разворачиваем и форматируем цепочку ошибок
        var causes []string
        cause := customErr.Unwrap()
        indent := "  "
        for cause != nil {
            causes = append(causes, fmt.Sprintf("%s↳ %v", indent, cause))
            cause = stderrors.Unwrap(cause)
            indent += "  "
        }

        if len(causes) > 0 {
            result += "\n" + strings.Join(causes, "\n")
        }

        return result
    }

    return err.Error()
}

// Пример логирования ошибки с использованием Fiber logger
func handleError(err error) {
    var customErr customerrors.Error
    if customerrors.As(err, &customErr) {
        // Структурированное логирование с дополнительными метаданными
        log.Errorw(customErr.Message,
            "statusCode", customErr.Code,
            "service", "UserService",
            "errorChain", formatErrorChain(customErr.Unwrap()))
    } else {
        log.Error(err.Error())
    }
}

// Пример использования в коде
func processUser(id string) error {
    if id == "" {
        return customerrors.ErrBadRequest.WithMessage("ID не может быть пустым")
    }

    // Предположим, что произошла ошибка при обращении к БД
    dbErr := stderrors.New("connection timeout")
    return customerrors.Wrap(dbErr, customerrors.StatusServiceUnavailable,
        "Ошибка при получении пользователя")
}

// Использование в обработчике
func userHandler(c *fiber.Ctx) error {
    id := c.Params("id")
    err := processUser(id)
    if err != nil {
        handleError(err)
        return err // Fiber middleware обработает HTTP-ответ
    }

    return c.JSON(fiber.Map{"success": true})
}

Структура пакета

errors/
  ├── constants.go    - HTTP коды состояния
  ├── predefined.go   - Предопределенные ошибки
  ├── service_error.go - Основной тип Error
  ├── handler.go      - HTTP-обработчики
  └── doc.go          - Документация

Примеры

В каталоге examples вы найдёте полные примеры использования пакета:

  • main.go - базовые примеры использования пакета
  • fiber_example.go - пример интеграции с фреймворком Fiber
  • logging_example.go - пример логирования ошибок (с вариантами для консольных приложений и через Fiber logger)

Для запуска примеров:

go run examples/main.go
go run examples/fiber_example.go
go run examples/logging_example.go

Цепочки ошибок и Unwrap

Пакет полностью поддерживает создание цепочек ошибок и стандартные механизмы работы с ними:

// Ошибка в репозитории
dbErr := stderrors.New("connection timeout")
repoErr := errors.Wrap(dbErr, errors.StatusInternalServerError, "Ошибка БД")

// Ошибка в сервисном слое
serviceErr := errors.Wrap(repoErr, errors.StatusInternalServerError, "Ошибка сервиса")

// В обработчике HTTP:
// 1. Получаем код и сообщение для клиента
statusCode, message := errors.ToHTTPError(serviceErr) // 500, "Ошибка сервиса: Ошибка БД: connection timeout"

// 2. Для отладки можем получить всю цепочку через Unwrap
cause := serviceErr
for cause != nil {
    fmt.Printf("-> %v\n", cause)
    cause = stderrors.Unwrap(cause)
}
// Выведет:
// -> Ошибка сервиса: Ошибка БД: connection timeout
// -> Ошибка БД: connection timeout
// -> connection timeout

Лицензия

Этот проект распространяется под лицензией MIT. См. файл LICENSE для более подробной информации.

Directories

Path Synopsis
Package errors предоставляет расширенную обработку ошибок для HTTP API и микросервисов, совместимую со стандартным пакетом errors Go 1.13+.
Package errors предоставляет расширенную обработку ошибок для HTTP API и микросервисов, совместимую со стандартным пакетом errors Go 1.13+.
Пример использования пакета ошибок с фреймворком Fiber
Пример использования пакета ошибок с фреймворком Fiber

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL