aboutsummaryrefslogblamecommitdiff
path: root/api/api.go
blob: 7b7be49257a2949796b5435ccaddc6abd63893bf (plain) (tree)

































































































































                                                                                                                                         
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)
	}
}