package api import ( "net/http" "unicode" "github.com/gin-gonic/gin" ) type Error struct { Code ErrorCode UserMessage string err error } func (e Error) Err() error { if e.err != nil { return e } return nil } func (e Error) Error() string { if e.err != nil { return e.err.Error() } return "" } func NewInternalError(err error) *Error { return &Error{InternalError, "internal error", err} } func ToSnake(in string) string { runes := []rune(in) length := len(runes) var out []rune for i := 0; i < length; i++ { if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) { out = append(out, '_') } out = append(out, unicode.ToLower(runes[i])) } return string(out) } type Response struct { StatusCode Status `json:"-"` ErrorCode ErrorCode `json:"-"` Status string `json:"status"` Code string `json:"code,omitempty"` Response interface{} `json:"response,omitempty"` Message string `json:"message,omitempty"` } func (r Response) populateStatus() Response { r.Status = ToSnake(r.StatusCode.String()) if r.ErrorCode != 0 { r.Code = ToSnake(r.ErrorCode.String()) } return r } func ErrorResponse(code ErrorCode, message string) Response { return Response{ StatusCode: NOK, ErrorCode: code, Message: message, } } func SuccessResponse(data interface{}) Response { return Response{ StatusCode: OK, Response: data, } } func WriteJsonResponse(response Response, c *gin.Context) { response = response.populateStatus() c.JSON(StatusToHttpCode(response.StatusCode, response.ErrorCode), response) } func WriteBinary(contentType string, b []byte, c *gin.Context) { c.Data(http.StatusOK, contentType, b) } type Middleware func(*gin.Context) *Error func M(handler Middleware) gin.HandlerFunc { return func(c *gin.Context) { err := handler(c) if err != nil { WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c) c.Error(err) c.Abort() } else { c.Next() } } } type Query interface { ValidateParams() *Error Run() (interface{}, *Error) } func RunQuery(query Query, c *gin.Context) { if err := query.ValidateParams(); err != nil { WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c) c.Error(err) return } if out, err := query.Run(); err != nil { WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c) c.Error(err) } else { WriteJsonResponse(SuccessResponse(out), c) } }