aboutsummaryrefslogtreecommitdiff
path: root/api/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'api/api.go')
-rw-r--r--api/api.go130
1 files changed, 130 insertions, 0 deletions
diff --git a/api/api.go b/api/api.go
new file mode 100644
index 0000000..7b7be49
--- /dev/null
+++ b/api/api.go
@@ -0,0 +1,130 @@
1package api
2
3import (
4 "net/http"
5 "unicode"
6
7 "github.com/gin-gonic/gin"
8)
9
10type Error struct {
11 Code ErrorCode
12 UserMessage string
13 err error
14}
15
16func (e Error) Err() error {
17 if e.err != nil {
18 return e
19 }
20
21 return nil
22}
23
24func (e Error) Error() string {
25 if e.err != nil {
26 return e.err.Error()
27 }
28
29 return ""
30}
31
32func NewInternalError(err error) *Error {
33 return &Error{InternalError, "internal error", err}
34}
35
36func ToSnake(in string) string {
37 runes := []rune(in)
38 length := len(runes)
39
40 var out []rune
41 for i := 0; i < length; i++ {
42 if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
43 out = append(out, '_')
44 }
45 out = append(out, unicode.ToLower(runes[i]))
46 }
47
48 return string(out)
49}
50
51type Response struct {
52 StatusCode Status `json:"-"`
53 ErrorCode ErrorCode `json:"-"`
54
55 Status string `json:"status"`
56 Code string `json:"code,omitempty"`
57 Response interface{} `json:"response,omitempty"`
58 Message string `json:"message,omitempty"`
59}
60
61func (r Response) populateStatus() Response {
62 r.Status = ToSnake(r.StatusCode.String())
63
64 if r.ErrorCode != 0 {
65 r.Code = ToSnake(r.ErrorCode.String())
66 }
67
68 return r
69}
70
71func ErrorResponse(code ErrorCode, message string) Response {
72 return Response{
73 StatusCode: NOK,
74 ErrorCode: code,
75 Message: message,
76 }
77}
78
79func SuccessResponse(data interface{}) Response {
80 return Response{
81 StatusCode: OK,
82 Response: data,
83 }
84}
85
86func WriteJsonResponse(response Response, c *gin.Context) {
87 response = response.populateStatus()
88
89 c.JSON(StatusToHttpCode(response.StatusCode, response.ErrorCode), response)
90}
91
92func WriteBinary(contentType string, b []byte, c *gin.Context) {
93 c.Data(http.StatusOK, contentType, b)
94}
95
96type Middleware func(*gin.Context) *Error
97
98func M(handler Middleware) gin.HandlerFunc {
99 return func(c *gin.Context) {
100 err := handler(c)
101
102 if err != nil {
103 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
104 c.Error(err)
105 c.Abort()
106 } else {
107 c.Next()
108 }
109 }
110}
111
112type Query interface {
113 ValidateParams() *Error
114 Run() (interface{}, *Error)
115}
116
117func RunQuery(query Query, c *gin.Context) {
118 if err := query.ValidateParams(); err != nil {
119 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
120 c.Error(err)
121 return
122 }
123
124 if out, err := query.Run(); err != nil {
125 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
126 c.Error(err)
127 } else {
128 WriteJsonResponse(SuccessResponse(out), c)
129 }
130}