all repos

onasty @ c0b5079c234cf570a675ada6bdd08b690e4e91c7

a one-time notes service

onasty/internal/transport/http/apiv1/response.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
refactor: common response for invalid bodies (#203), 9 months ago
1
package apiv1
2
3
import (
4
	"errors"
5
	"log/slog"
6
	"net/http"
7
8
	"github.com/gin-gonic/gin"
9
	"github.com/olexsmir/onasty/internal/jwtutil"
10
	"github.com/olexsmir/onasty/internal/models"
11
	"github.com/olexsmir/onasty/internal/service/authsrv"
12
	"github.com/olexsmir/onasty/internal/service/notesrv"
13
)
14
15
var ErrUnauthorized = errors.New("unauthorized")
16
17
type response struct {
18
	Message string `json:"message"`
19
}
20
21
func errorResponse(c *gin.Context, err error) {
22
	if errors.Is(err, authsrv.ErrProviderNotSupported) ||
23
		errors.Is(err, models.ErrResetPasswordTokenAlreadyUsed) ||
24
		errors.Is(err, models.ErrResetPasswordTokenExpired) ||
25
		errors.Is(err, models.ErrUserEmailIsAlreadyInUse) ||
26
		errors.Is(err, models.ErrUserIsAlreadyVerified) ||
27
		errors.Is(err, models.ErrUserIsNotActivated) ||
28
		errors.Is(err, models.ErrUserInvalidEmail) ||
29
		errors.Is(err, models.ErrUserInvalidPassword) ||
30
		errors.Is(err, models.ErrUserNotFound) ||
31
		// notes
32
		errors.Is(err, notesrv.ErrNotePasswordNotProvided) ||
33
		errors.Is(err, models.ErrNoteContentIsEmpty) ||
34
		errors.Is(err, models.ErrNoteCannotBeKept) ||
35
		errors.Is(err, models.ErrNoteSlugIsAlreadyInUse) ||
36
		errors.Is(err, models.ErrNoteSlugIsInvalid) {
37
		newError(c, http.StatusBadRequest, err.Error())
38
		return
39
	}
40
41
	if errors.Is(err, models.ErrNoteExpired) {
42
		newError(c, http.StatusGone, err.Error())
43
		return
44
	}
45
46
	if errors.Is(err, models.ErrNoteNotFound) ||
47
		errors.Is(err, models.ErrVerificationTokenNotFound) {
48
		newErrorStatus(c, http.StatusNotFound, err.Error())
49
		return
50
	}
51
52
	if errors.Is(err, ErrUnauthorized) ||
53
		errors.Is(err, jwtutil.ErrTokenExpired) ||
54
		errors.Is(err, jwtutil.ErrTokenSignatureInvalid) {
55
		newErrorStatus(c, http.StatusUnauthorized, err.Error())
56
		return
57
	}
58
59
	newInternalError(c, err)
60
}
61
62
func invalidRequest(c *gin.Context) {
63
	newError(c, http.StatusBadRequest, "invalid request")
64
}
65
66
func newError(c *gin.Context, status int, msg string) {
67
	slog.ErrorContext(c.Request.Context(), msg, "status", status)
68
	c.AbortWithStatusJSON(status, response{msg})
69
}
70
71
func newErrorStatus(c *gin.Context, status int, msg string) {
72
	slog.ErrorContext(c.Request.Context(), msg, "status", status)
73
	c.AbortWithStatus(status)
74
}
75
76
func newInternalError(c *gin.Context, err error, msg ...string) {
77
	slog.ErrorContext(c.Request.Context(), err.Error(), "status", "internal error")
78
79
	if len(msg) != 0 {
80
		c.AbortWithStatusJSON(http.StatusInternalServerError, response{
81
			Message: msg[0],
82
		})
83
		return
84
	}
85
86
	c.AbortWithStatusJSON(http.StatusInternalServerError, response{
87
		Message: "internal error",
88
	})
89
}