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"})
|
|||
|
|
}
|
|||
|
|
}
|