Обработка ошибок в Go-сервисе
Вопрос
Как вы обрабатываете ошибки в Go-сервисе от репозитория до HTTP-ответа?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Ошибки как значения, проверка сразу после вызова
Обёртка с контекстом через `%w` на каждом уровне, без дублей логирования
Sentinel и свои типы для доменных ошибок, проверка errors.Is/As
Маппинг на HTTP-статус в одном месте (handler или middleware)
Логировать один раз на верхнем уровне, клиенту не отдавать внутренние детали
recover в middleware на случай паники
Что могут спросить следом
- Как понять, где именно возникла ошибка без стека?
- Когда ошибку можно проигнорировать?
Разбор
В репозитории ошибку драйвера превращаю в доменную там, где это имеет смысл: sql.ErrNoRows становится ErrNotFound, нарушение уникальности становится ErrConflict. Остальное оборачиваю с контекстом: fmt.Errorf("get order %d: %w", id, err). На уровне сервиса тоже добавляю контекст, но не логирую: если логировать на каждом уровне, одна ошибка даст пять строк в логах. Вверху, в HTTP-обработчике или общем middleware, одна функция маппит ошибки на статусы через errors.Is и errors.As: NotFound в 404, ValidationError в 400 с полями, остальное в 500 с общим текстом, а подробности с request id в лог. Цепочка контекстов в сообщении заменяет стек: по ней видно путь. Плюс recover-middleware, чтобы паника в одном запросе не роняла сервер. Игнорирую ошибку только осознанно и с комментарием, например Close у файла, открытого на чтение.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.