]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front.git/blob - api/api.go
Refactor Portfolio balance.
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front.git] / api / api.go
1 package api
2
3 import (
4 "net/http"
5 "unicode"
6
7 "github.com/gin-gonic/gin"
8 )
9
10 var CONFIG Config
11
12 type Config struct {
13 JwtSecret string `toml:"jwt_secret"`
14 PasswordResetSecret string `toml:"password_reset_secret"`
15 FreeSMSUser string `toml:"free_sms_user"`
16 FreeSMSPass string `toml:"free_sms_pass"`
17 }
18
19 func SetConfig(config Config) {
20 CONFIG = config
21
22 JWT_SECRET = []byte(config.JwtSecret)
23 PASSWORD_RESET_SECRET = []byte(config.PasswordResetSecret)
24 }
25
26 type Error struct {
27 Code ErrorCode
28 UserMessage string
29 err error
30 }
31
32 func (e Error) Err() error {
33 if e.err != nil {
34 return e
35 }
36
37 return nil
38 }
39
40 func (e Error) Error() string {
41 if e.err != nil {
42 return e.err.Error()
43 }
44
45 return ""
46 }
47
48 func ErrorIs(err error, code ErrorCode) bool {
49 if err == nil {
50 return false
51 }
52
53 if apiError, ok := err.(*Error); !ok {
54 return false
55 } else {
56 return apiError.Code == code
57 }
58 }
59
60 func NewInternalError(err error) *Error {
61 return &Error{InternalError, "internal error", err}
62 }
63
64 func ToSnake(in string) string {
65 runes := []rune(in)
66 length := len(runes)
67
68 var out []rune
69 for i := 0; i < length; i++ {
70 if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
71 out = append(out, '_')
72 }
73 out = append(out, unicode.ToLower(runes[i]))
74 }
75
76 return string(out)
77 }
78
79 type Response struct {
80 StatusCode Status `json:"-"`
81 ErrorCode ErrorCode `json:"-"`
82
83 Status string `json:"status"`
84 Code string `json:"code,omitempty"`
85 Response interface{} `json:"response,omitempty"`
86 Message string `json:"message,omitempty"`
87 }
88
89 func (r Response) populateStatus() Response {
90 r.Status = ToSnake(r.StatusCode.String())
91
92 if r.ErrorCode != 0 {
93 r.Code = ToSnake(r.ErrorCode.String())
94 }
95
96 return r
97 }
98
99 func ErrorResponse(code ErrorCode, message string) Response {
100 return Response{
101 StatusCode: NOK,
102 ErrorCode: code,
103 Message: message,
104 }
105 }
106
107 func SuccessResponse(data interface{}) Response {
108 return Response{
109 StatusCode: OK,
110 Response: data,
111 }
112 }
113
114 func WriteJsonResponse(response Response, c *gin.Context) {
115 response = response.populateStatus()
116
117 c.JSON(StatusToHttpCode(response.StatusCode, response.ErrorCode), response)
118 }
119
120 func WriteBinary(contentType string, b []byte, c *gin.Context) {
121 c.Data(http.StatusOK, contentType, b)
122 }
123
124 type Middleware func(*gin.Context) *Error
125
126 func M(handler Middleware) gin.HandlerFunc {
127 return func(c *gin.Context) {
128 err := handler(c)
129
130 if err != nil {
131 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
132 c.Error(err)
133 c.Abort()
134 } else {
135 c.Next()
136 }
137 }
138 }
139
140 type Query interface {
141 ValidateParams() *Error
142 Run() (interface{}, *Error)
143 }
144
145 func RunQuery(query Query, c *gin.Context) {
146 if err := query.ValidateParams(); err != nil {
147 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
148 c.Error(err)
149 return
150 }
151
152 if out, err := query.Run(); err != nil {
153 WriteJsonResponse(ErrorResponse(err.Code, err.UserMessage), c)
154 c.Error(err)
155 } else {
156 WriteJsonResponse(SuccessResponse(out), c)
157 }
158 }