feat(error): Create api error. WIP
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -8,15 +10,12 @@ import (
|
||||
func SimpleTokens(tokens []string, forbiddenHandler gin.HandlerFunc) gin.HandlerFunc {
|
||||
if forbiddenHandler == nil {
|
||||
forbiddenHandler = func(c *gin.Context) {
|
||||
c.AbortWithStatusJSON(403, map[string]string{
|
||||
"message": "Forbidden",
|
||||
"debugId": c.GetString(string(ContextKey_RequestID)),
|
||||
})
|
||||
errorHandler(c, aerr.NewForbidden())
|
||||
}
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
|
||||
requestToken := c.GetHeader(string(HeaderKey_Token))
|
||||
requestToken := c.GetHeader(string(constant.HeaderKey_Token))
|
||||
isAuthorized := false
|
||||
for _, key := range tokens {
|
||||
if key == requestToken {
|
||||
|
@ -1,31 +0,0 @@
|
||||
package ginutils
|
||||
|
||||
type contextKey string
|
||||
|
||||
//nolint:exported // keeping the enum simple and readable.
|
||||
const (
|
||||
ContextKey_Logger contextKey = "logger"
|
||||
ContextKey_RequestID contextKey = "requestID"
|
||||
)
|
||||
|
||||
type headerKey string
|
||||
|
||||
//nolint:exported // keeping the enum simple and readable.
|
||||
const (
|
||||
HeaderKey_RequestID headerKey = "X-REQUEST-ID"
|
||||
HeaderKey_Token headerKey = "X-TOKEN"
|
||||
)
|
||||
|
||||
type logField string
|
||||
|
||||
//nolint:exported // keeping the enum simple and readable.
|
||||
const (
|
||||
LogField_RequestID logField = "request_id"
|
||||
LogField_Method logField = "method"
|
||||
LogField_CanonPath logField = "canon_path"
|
||||
LogField_Path logField = "path"
|
||||
LogField_StatusCode logField = "status_code"
|
||||
LogField_Username logField = "username"
|
||||
LogField_IP logField = "real_ip"
|
||||
LogField_Duration logField = "duration_ms"
|
||||
)
|
@ -3,6 +3,7 @@ package ginutils
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/webserver"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -16,17 +17,17 @@ func Log(l *logrus.Entry) gin.HandlerFunc {
|
||||
|
||||
// construct default fields
|
||||
fields := logrus.Fields{
|
||||
string(LogField_IP): webserver.GetClientIP(c.Request),
|
||||
string(constant.LogField_IP): webserver.GetClientIP(c.Request),
|
||||
// Request information
|
||||
string(LogField_Method): c.Request.Method,
|
||||
string(LogField_CanonPath): c.FullPath(),
|
||||
string(LogField_Path): c.Request.URL.String(),
|
||||
string(LogField_RequestID): c.GetString(string(ContextKey_RequestID)),
|
||||
string(constant.LogField_Method): c.Request.Method,
|
||||
string(constant.LogField_CanonPath): c.FullPath(),
|
||||
string(constant.LogField_Path): c.Request.URL.String(),
|
||||
string(constant.LogField_RequestID): c.GetString(string(constant.ContextKey_RequestID)),
|
||||
}
|
||||
|
||||
// create the logrus entry and add it to gin context
|
||||
log := l.Logger.WithFields(fields)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
|
||||
log.Info("[start]")
|
||||
|
||||
@ -34,15 +35,15 @@ func Log(l *logrus.Entry) gin.HandlerFunc {
|
||||
|
||||
log.WithFields(
|
||||
logrus.Fields{
|
||||
string(LogField_Duration): time.Since(start).Microseconds(),
|
||||
string(LogField_StatusCode): c.Writer.Status(),
|
||||
string(constant.LogField_Duration): time.Since(start).Microseconds(),
|
||||
string(constant.LogField_StatusCode): c.Writer.Status(),
|
||||
}).Info("[end]")
|
||||
}
|
||||
}
|
||||
|
||||
// GetLogger will retrieve a logger instance from gin context and return it or return false.
|
||||
func GetLogger(c *gin.Context) (*logrus.Entry, bool) {
|
||||
if log, exist := c.Get(string(ContextKey_Logger)); exist {
|
||||
if log, exist := c.Get(string(constant.ContextKey_Logger)); exist {
|
||||
return log.(*logrus.Entry), true
|
||||
}
|
||||
|
||||
@ -51,7 +52,7 @@ func GetLogger(c *gin.Context) (*logrus.Entry, bool) {
|
||||
|
||||
// GetLoggerWithField will add a key and value field to the logger, update the gin context, and return the new logger.
|
||||
func GetLoggerWithField(c *gin.Context, key string, value interface{}) *logrus.Entry {
|
||||
iLog, exist := c.Get(string(ContextKey_Logger))
|
||||
iLog, exist := c.Get(string(constant.ContextKey_Logger))
|
||||
if !exist {
|
||||
panic("no logger in context")
|
||||
}
|
||||
@ -62,13 +63,13 @@ func GetLoggerWithField(c *gin.Context, key string, value interface{}) *logrus.E
|
||||
}
|
||||
|
||||
log = log.WithField(key, value)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
return log
|
||||
}
|
||||
|
||||
// GetLoggerWithFields will add provided fields to the logger, update the gin context, and return the new logger.
|
||||
func GetLoggerWithFields(c *gin.Context, fields logrus.Fields) *logrus.Entry {
|
||||
iLog, exist := c.Get(string(ContextKey_Logger))
|
||||
iLog, exist := c.Get(string(constant.ContextKey_Logger))
|
||||
if !exist {
|
||||
panic("no logger in context")
|
||||
}
|
||||
@ -79,6 +80,6 @@ func GetLoggerWithFields(c *gin.Context, fields logrus.Fields) *logrus.Entry {
|
||||
}
|
||||
|
||||
log = log.WithFields(fields)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
return log
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -15,10 +16,7 @@ import (
|
||||
func Recovery(handler gin.HandlerFunc) gin.HandlerFunc {
|
||||
if handler == nil {
|
||||
handler = func(c *gin.Context) {
|
||||
c.AbortWithStatusJSON(500, map[string]string{
|
||||
"message": "Internal Server Error",
|
||||
"debugId": c.GetString(string(ContextKey_RequestID)),
|
||||
})
|
||||
errorHandler(c, aerr.NewInternalServerError())
|
||||
}
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
@ -37,7 +35,6 @@ func Recovery(handler gin.HandlerFunc) gin.HandlerFunc {
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
gin.Recovery()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@ -10,16 +11,16 @@ import (
|
||||
func RequestID() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
requestID := c.GetHeader(string(HeaderKey_RequestID))
|
||||
requestID := c.GetHeader(string(constant.HeaderKey_RequestID))
|
||||
if _, err := uuid.Parse(requestID); err != nil {
|
||||
// no request ID or invalid. let's generate a new one
|
||||
requestID = uuid.New().String()
|
||||
}
|
||||
|
||||
// Adding to context
|
||||
c.Set(string(ContextKey_RequestID), requestID)
|
||||
c.Set(string(constant.ContextKey_RequestID), requestID)
|
||||
// Add request-id to the header before sending the response
|
||||
c.Header(string(HeaderKey_RequestID), requestID)
|
||||
c.Header(string(constant.HeaderKey_RequestID), requestID)
|
||||
// Let's the next part run
|
||||
c.Next()
|
||||
}
|
||||
|
50
ginutils/wrapper.go
Normal file
50
ginutils/wrapper.go
Normal file
@ -0,0 +1,50 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// HandlerFunc represent the type of function expected by the wrapper.
|
||||
type HandlerFunc func(*gin.Context) error
|
||||
|
||||
// HandlerWrapper will wrap a handler to handle error.
|
||||
func HandlerWrapper(h HandlerFunc) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
err := h(c)
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func errorHandler(c *gin.Context, err error) {
|
||||
//nolint: errorlint // Ignore linter to avoid creating useless complexity in the code.
|
||||
switch e := err.(type) {
|
||||
case *aerr.Error:
|
||||
log := GetLoggerWithFields(c, logrus.Fields{
|
||||
string(constant.LogField_Error): e.Error(),
|
||||
string(constant.LogField_ErrorCode): e.Code,
|
||||
})
|
||||
log.Warn("An error occurred")
|
||||
if e.DebugId == "" {
|
||||
e = e.SetDebugID(c.GetString(string(constant.ContextKey_RequestID)))
|
||||
}
|
||||
c.AbortWithStatusJSON(e.HttpCode(), e)
|
||||
default:
|
||||
log := GetLoggerWithFields(c, logrus.Fields{
|
||||
string(constant.LogField_Error): e.Error(),
|
||||
string(constant.LogField_ErrorCode): "500",
|
||||
})
|
||||
log.Warn("An error occurred")
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, aerr.Error{
|
||||
Msg: e.Error(),
|
||||
Code: 500,
|
||||
DebugId: c.GetString(string(constant.ContextKey_RequestID)),
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user