43 lines
1.6 KiB
Go
43 lines
1.6 KiB
Go
package handlers
|
||
|
||
import (
|
||
"errors"
|
||
"log/slog"
|
||
"net/http"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
|
||
"building-mgmt/internal/middleware"
|
||
"building-mgmt/internal/repository"
|
||
)
|
||
|
||
// respondError отдаёт JSON-ответ по классу ошибки репозитория.
|
||
//
|
||
// Тексты ошибок БД наружу не попадают: инфраструктурные ошибки
|
||
// пишутся в лог и превращаются в 500, а на клиент уходят только
|
||
// фиксированные сообщения. Если endpoint'у нужно своё сообщение,
|
||
// он ветвится через errors.Is(...) сам, до вызова respondError.
|
||
func respondError(c *gin.Context, err error) {
|
||
// Общие атрибуты, чтобы ошибку можно было найти по запросу.
|
||
attrs := []any{
|
||
"err", err,
|
||
"request_id", middleware.RequestIDFrom(c),
|
||
"method", c.Request.Method,
|
||
"path", c.Request.URL.Path,
|
||
}
|
||
|
||
switch {
|
||
case errors.Is(err, repository.ErrNotFound):
|
||
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
||
case errors.Is(err, repository.ErrConflict):
|
||
c.JSON(http.StatusConflict, gin.H{"error": "conflict"})
|
||
case errors.Is(err, repository.ErrInvalid):
|
||
// Нарушение ограничения — это баг вызывающего кода, логируем.
|
||
slog.Warn("constraint violation", attrs...)
|
||
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "invalid request"})
|
||
default:
|
||
slog.Error("internal error", attrs...)
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
|
||
}
|
||
}
|