From e39d73f2dad0fe802e65a3328e72260388488037 Mon Sep 17 00:00:00 2001 From: rxdn <29165304+rxdn@users.noreply.github.com> Date: Mon, 11 Nov 2024 23:19:54 +0000 Subject: [PATCH] WIP: Better error handling --- app/errors.go | 29 ++++++++++++++++++++++ app/http/endpoints/api/panel/panellist.go | 29 +++++++++++----------- app/http/middleware/errorhandler.go | 30 +++++++++++++++++++++++ app/http/server.go | 3 ++- 4 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 app/errors.go create mode 100644 app/http/middleware/errorhandler.go diff --git a/app/errors.go b/app/errors.go new file mode 100644 index 0000000..9ea762e --- /dev/null +++ b/app/errors.go @@ -0,0 +1,29 @@ +package app + +import "fmt" + +type ApiError struct { + InternalError error + ExternalMessage string +} + +var _ error = (*ApiError)(nil) + +func NewError(internalError error, externalMessage string) *ApiError { + return &ApiError{ + InternalError: internalError, + ExternalMessage: externalMessage, + } +} + +func NewServerError(internalError error) *ApiError { + return NewError(internalError, "An internal server error occurred") +} + +func (e *ApiError) Error() string { + return fmt.Sprintf("internal error: %v, external message: %s", e.InternalError, e.ExternalMessage) +} + +func (e *ApiError) Unwrap() error { + return e.InternalError +} diff --git a/app/http/endpoints/api/panel/panellist.go b/app/http/endpoints/api/panel/panellist.go index 071056c..2344d4a 100644 --- a/app/http/endpoints/api/panel/panellist.go +++ b/app/http/endpoints/api/panel/panellist.go @@ -2,16 +2,17 @@ package api import ( "context" + "github.com/TicketsBot/GoPanel/app" dbclient "github.com/TicketsBot/GoPanel/database" - "github.com/TicketsBot/GoPanel/utils" "github.com/TicketsBot/GoPanel/utils/types" "github.com/TicketsBot/database" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" + "net/http" "strconv" ) -func ListPanels(ctx *gin.Context) { +func ListPanels(c *gin.Context) { type panelResponse struct { database.Panel WelcomeMessage *types.CustomEmbed `json:"welcome_message"` @@ -23,23 +24,23 @@ func ListPanels(ctx *gin.Context) { AccessControlList []database.PanelAccessControlRule `json:"access_control_list"` } - guildId := ctx.Keys["guildid"].(uint64) + guildId := c.Keys["guildid"].(uint64) - panels, err := dbclient.Client.Panel.GetByGuildWithWelcomeMessage(ctx, guildId) + panels, err := dbclient.Client.Panel.GetByGuildWithWelcomeMessage(c, guildId) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + _ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err)) return } - accessControlLists, err := dbclient.Client.PanelAccessControlRules.GetAllForGuild(ctx, guildId) + accessControlLists, err := dbclient.Client.PanelAccessControlRules.GetAllForGuild(c, guildId) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + _ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err)) return } - allFields, err := dbclient.Client.EmbedFields.GetAllFieldsForPanels(ctx, guildId) + allFields, err := dbclient.Client.EmbedFields.GetAllFieldsForPanels(c, guildId) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + _ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err)) return } @@ -56,7 +57,7 @@ func ListPanels(ctx *gin.Context) { var mentions []string // get if we should mention the ticket opener - shouldMention, err := dbclient.Client.PanelUserMention.ShouldMentionUser(ctx, p.PanelId) + shouldMention, err := dbclient.Client.PanelUserMention.ShouldMentionUser(c, p.PanelId) if err != nil { return err } @@ -66,7 +67,7 @@ func ListPanels(ctx *gin.Context) { } // get role mentions - roles, err := dbclient.Client.PanelRoleMentions.GetRoles(ctx, p.PanelId) + roles, err := dbclient.Client.PanelRoleMentions.GetRoles(c, p.PanelId) if err != nil { return err } @@ -76,7 +77,7 @@ func ListPanels(ctx *gin.Context) { mentions = append(mentions, strconv.FormatUint(roleId, 10)) } - teamIds, err := dbclient.Client.PanelTeams.GetTeamIds(ctx, p.PanelId) + teamIds, err := dbclient.Client.PanelTeams.GetTeamIds(c, p.PanelId) if err != nil { return err } @@ -113,9 +114,9 @@ func ListPanels(ctx *gin.Context) { } if err := group.Wait(); err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + _ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err)) return } - ctx.JSON(200, wrapped) + c.JSON(200, wrapped) } diff --git a/app/http/middleware/errorhandler.go b/app/http/middleware/errorhandler.go new file mode 100644 index 0000000..b16e7f3 --- /dev/null +++ b/app/http/middleware/errorhandler.go @@ -0,0 +1,30 @@ +package middleware + +import ( + "errors" + "github.com/TicketsBot/GoPanel/app" + "github.com/gin-gonic/gin" +) + +type ErrorResponse struct { + Error string `json:"error"` +} + +func ErrorHandler(c *gin.Context) { + c.Next() + + if len(c.Errors) > 0 { + var message string + + var apiError *app.ApiError + if errors.As(c.Errors[0], &apiError) { + message = apiError.ExternalMessage + } else { + message = "An error occurred processing your request" + } + + c.JSON(-1, ErrorResponse{ + Error: message, + }) + } +} diff --git a/app/http/server.go b/app/http/server.go index fbe220d..353e2d8 100644 --- a/app/http/server.go +++ b/app/http/server.go @@ -33,6 +33,7 @@ func StartServer(logger *zap.Logger, sm *livechat.SocketManager) { router := gin.New() router.Use(gin.Recovery()) router.Use(middleware.Logging(logger)) + router.Use(middleware.ErrorHandler) router.RemoteIPHeaders = config.Conf.Server.RealIpHeaders if err := router.SetTrustedProxies(config.Conf.Server.TrustedProxies); err != nil { @@ -58,7 +59,7 @@ func StartServer(logger *zap.Logger, sm *livechat.SocketManager) { metricRouter := gin.New() metricRouter.Use(gin.Recovery()) metricRouter.Use(middleware.Logging(logger)) - + monitor.Expose(metricRouter) go func() {