/
handlers.go
193 lines (175 loc) · 6.4 KB
/
handlers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package api
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
var persistence *Persistence
// function used to set global persistence layer
func SetPersistence(host string, port int, username,
password, database string) *Persistence {
// generate new persistence instance
persistence = NewPersistence(host, port, username, password,
database)
return persistence
}
// API handler used to serve health check request
func HealthCheckHandler(ctx *gin.Context) {
log.Info("received request for health check handler")
ctx.JSON(http.StatusOK, gin.H{"http_code": http.StatusOK,
"message": "Service running"})
}
// API handler used to retreive location for a given entity
func GetEntityHandler(ctx *gin.Context) {
log.Info("received request for location")
// retrieve entity ID from URL params and parse into UUID
entityId, err := uuid.Parse(ctx.Param("entityId"))
if err != nil {
log.Error(fmt.Errorf("unable to parse entity ID: %+v", err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid entity ID format"})
return
}
// get entity (including location) from database
entity, err := persistence.GetEntity(entityId)
if err != nil {
log.Error(fmt.Errorf("unable to retrieve entity: %+v", err))
switch err {
case ErrEntityNotFound:
ctx.AbortWithStatusJSON(http.StatusNotFound, gin.H{"http_code": http.StatusNotFound,
"message": "Cannot find specified entity"})
default:
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
}
return
}
ctx.JSON(http.StatusOK, gin.H{"http_code": http.StatusOK, "entity": entity})
}
// API handler used to retrieve list of current entities
func GetEntitiesHandler(ctx *gin.Context) {
log.Info("received request to retrieve entities")
// get entities from database and return
entities, err := persistence.GetEntities()
if err != nil {
log.Error(fmt.Errorf("unable to retrieve entities from database: %+v", err))
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
return
}
ctx.JSON(http.StatusOK, gin.H{"http_code": http.StatusOK,
"entities": entities})
}
// API handler used to register new entity
func RegisterEntityHandler(ctx *gin.Context) {
log.Info("received request to register new entity")
var e struct {
Meta map[string]interface{}
}
if err := ctx.ShouldBind(&e); err != nil {
log.Error(fmt.Errorf("unable to parse request body: %+v", err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid request body"})
}
if err := persistence.RegisterEntity(e.Meta); err != nil {
log.Error(fmt.Errorf("unable to register new entity: %+v", err))
switch err {
case ErrInvalidEntityMeta:
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid entity metadata"})
default:
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
}
return
}
ctx.JSON(http.StatusCreated, gin.H{"http_code": http.StatusCreated,
"message": "Successfully created entity"})
}
// API handler used to register new location for a given entity
func RegisterLocationHandler(ctx *gin.Context) {
log.Info("received request to register new location")
// retrieve entity ID from URL params and parse into UUID
entityId, err := uuid.Parse(ctx.Param("entityId"))
if err != nil {
log.Error(fmt.Errorf("unable to parse entity ID: %+v", err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid entity ID format"})
return
}
var l GeoLocation
if err := ctx.ShouldBind(&l); err != nil {
log.Error(fmt.Errorf("unable to parse request body: %+v", err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid location"})
return
}
// return 400 if GeoLocation is not valid i.e. longitude and latitude do
// not fall in allowed ranges
if !l.IsValid() {
log.Error(fmt.Sprintf("cannot register location: received invalid coordinates %+v", l))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid location"})
return
}
// get entity from database. if entity cannot be found, return 404
_, err = persistence.GetEntity(entityId)
if err != nil {
log.Error(fmt.Errorf("unable to retrieve entity: %+v", err))
switch err {
case ErrEntityNotFound:
ctx.AbortWithStatusJSON(http.StatusNotFound, gin.H{"http_code": http.StatusNotFound,
"message": "Cannot find specified entity"})
default:
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
}
return
}
// set entity location in database
if err := persistence.SetEntityLocation(entityId, l); err != nil {
log.Error(fmt.Errorf("unable to set location for entity: %+v", err))
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
return
}
ctx.JSON(http.StatusOK, gin.H{"http_code": http.StatusOK,
"message": "Successfully updated location"})
}
// API handler used to delete a given entity
func DeleteEntityHandler(ctx *gin.Context) {
log.Info("received request to delete entity")
// retrieve entity ID from URL params and parse into UUID
entityId, err := uuid.Parse(ctx.Param("entityId"))
if err != nil {
log.Error(fmt.Errorf("unable to parse entity ID: %+v", err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"http_code": http.StatusBadRequest,
"message": "Invalid entity ID format"})
return
}
// get entity from database. if entity cannot be found, return 404
_, err = persistence.GetEntity(entityId)
if err != nil {
log.Error(fmt.Errorf("unable to retrieve entity: %+v", err))
switch err {
case ErrEntityNotFound:
ctx.AbortWithStatusJSON(http.StatusNotFound, gin.H{"http_code": http.StatusNotFound,
"message": "Cannot find specified entity"})
default:
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
}
return
}
// delete entity from database
if err := persistence.DeleteEntity(entityId); err != nil {
log.Error(fmt.Errorf("unable to delete entity: %+v", err))
ctx.AbortWithStatusJSON(http.StatusInternalServerError,
InternalServerErrorResponse)
return
}
ctx.JSON(http.StatusOK, gin.H{"http_code": http.StatusOK,
"message": "Successfully deleted entity"})
}