You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.0 KiB
Go
150 lines
4.0 KiB
Go
// Package httputil provides HTTP utility functions for the KnowFoolery application.
|
|
package httputil
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v3"
|
|
|
|
"knowfoolery/backend/shared/domain/errors"
|
|
)
|
|
|
|
// ErrorResponse represents a standard error response.
|
|
type ErrorResponse struct {
|
|
Error bool `json:"error"`
|
|
Code string `json:"code,omitempty"`
|
|
Message string `json:"message"`
|
|
Details string `json:"details,omitempty"`
|
|
}
|
|
|
|
// NewErrorResponse creates a new ErrorResponse.
|
|
func NewErrorResponse(code, message, details string) ErrorResponse {
|
|
return ErrorResponse{
|
|
Error: true,
|
|
Code: code,
|
|
Message: message,
|
|
Details: details,
|
|
}
|
|
}
|
|
|
|
// SendError sends an error response with the appropriate HTTP status code.
|
|
func SendError(c fiber.Ctx, err error) error {
|
|
statusCode, response := MapError(err)
|
|
return c.Status(statusCode).JSON(response)
|
|
}
|
|
|
|
// MapError maps a domain error to an HTTP status code and response.
|
|
func MapError(err error) (int, ErrorResponse) {
|
|
if err == nil {
|
|
return fiber.StatusInternalServerError, NewErrorResponse(
|
|
"INTERNAL",
|
|
"An unexpected error occurred",
|
|
"",
|
|
)
|
|
}
|
|
|
|
domainErr, ok := err.(*errors.DomainError)
|
|
if !ok {
|
|
return fiber.StatusInternalServerError, NewErrorResponse(
|
|
"INTERNAL",
|
|
"An unexpected error occurred",
|
|
err.Error(),
|
|
)
|
|
}
|
|
|
|
statusCode := mapErrorCodeToStatus(domainErr.Code)
|
|
return statusCode, NewErrorResponse(
|
|
domainErr.Code.String(),
|
|
domainErr.Message,
|
|
"",
|
|
)
|
|
}
|
|
|
|
// mapErrorCodeToStatus maps an error code to an HTTP status code.
|
|
func mapErrorCodeToStatus(code errors.ErrorCode) int {
|
|
switch code {
|
|
case errors.CodeNotFound, errors.CodeQuestionNotFound, errors.CodeUserNotFound:
|
|
return fiber.StatusNotFound
|
|
case errors.CodeInvalidInput, errors.CodeValidationFailed, errors.CodeInvalidPlayerName, errors.CodeInvalidAnswer:
|
|
return fiber.StatusBadRequest
|
|
case errors.CodeUnauthorized, errors.CodeInvalidToken, errors.CodeTokenExpired:
|
|
return fiber.StatusUnauthorized
|
|
case errors.CodeForbidden, errors.CodeMFARequired, errors.CodeEmailNotVerified:
|
|
return fiber.StatusForbidden
|
|
case errors.CodeConflict, errors.CodeUserAlreadyExists, errors.CodeGameInProgress:
|
|
return fiber.StatusConflict
|
|
case errors.CodeRateLimitExceeded:
|
|
return fiber.StatusTooManyRequests
|
|
case errors.CodeSessionExpired, errors.CodeSessionNotActive:
|
|
return fiber.StatusGone
|
|
case errors.CodeMaxAttemptsReached, errors.CodeNoQuestionsAvailable:
|
|
return fiber.StatusUnprocessableEntity
|
|
case errors.CodeInternal:
|
|
return fiber.StatusInternalServerError
|
|
default:
|
|
return fiber.StatusInternalServerError
|
|
}
|
|
}
|
|
|
|
// BadRequest sends a 400 Bad Request response.
|
|
func BadRequest(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusBadRequest).JSON(NewErrorResponse(
|
|
"BAD_REQUEST",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// Unauthorized sends a 401 Unauthorized response.
|
|
func Unauthorized(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(NewErrorResponse(
|
|
"UNAUTHORIZED",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// Forbidden sends a 403 Forbidden response.
|
|
func Forbidden(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusForbidden).JSON(NewErrorResponse(
|
|
"FORBIDDEN",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// NotFound sends a 404 Not Found response.
|
|
func NotFound(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusNotFound).JSON(NewErrorResponse(
|
|
"NOT_FOUND",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// Conflict sends a 409 Conflict response.
|
|
func Conflict(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusConflict).JSON(NewErrorResponse(
|
|
"CONFLICT",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// TooManyRequests sends a 429 Too Many Requests response.
|
|
func TooManyRequests(c fiber.Ctx, message string, retryAfter int) error {
|
|
c.Set("Retry-After", string(rune(retryAfter)))
|
|
return c.Status(fiber.StatusTooManyRequests).JSON(NewErrorResponse(
|
|
"RATE_LIMIT_EXCEEDED",
|
|
message,
|
|
"",
|
|
))
|
|
}
|
|
|
|
// InternalError sends a 500 Internal Server Error response.
|
|
func InternalError(c fiber.Ctx, message string) error {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(NewErrorResponse(
|
|
"INTERNAL",
|
|
message,
|
|
"",
|
|
))
|
|
}
|