1
1
package main
2
2
3
3
import (
4
+ "context"
4
5
"encoding/base64"
5
6
"encoding/json"
7
+ "fmt"
6
8
"net/http"
7
- "os "
9
+ "net/http/httptest "
8
10
"time"
9
11
10
- "github.com/gorilla/handlers "
11
- "github.com/gorilla/mux "
12
+ "github.com/pressly/chi "
13
+ "github.com/rs/xlog "
12
14
)
13
15
14
- // some middleware handlers
15
- func timeoutHandler (h http.Handler ) http.Handler {
16
- return http .TimeoutHandler (h , 10 * time .Second , "timed out" )
17
- }
16
+ func logHandler (next http.Handler ) http.Handler {
17
+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
18
+ rec := httptest .NewRecorder ()
19
+ t1 := time .Now ()
20
+ next .ServeHTTP (rec , r )
21
+
22
+ l := xlog .FromRequest (r )
23
+ for k , v := range rec .Header () {
24
+ w .Header ()[k ] = v
25
+ }
26
+ w .WriteHeader (rec .Code )
27
+ w .Write (rec .Body .Bytes ())
18
28
19
- func loggingHandler (h http.Handler ) http.Handler {
20
- return handlers .CombinedLoggingHandler (os .Stdout , h )
29
+ t2 := time .Now ()
30
+ l .Info (xlog.F {
31
+ "duration" : t2 .Sub (t1 ),
32
+ "status" : rec .Code ,
33
+ "size" : rec .Body .Len (),
34
+ })
35
+ })
21
36
}
22
37
23
- // the real handlers
24
- func alertHandler (db store ) func (w http.ResponseWriter , r * http.Request ) {
25
- return func (w http.ResponseWriter , r * http.Request ) {
26
- vars := mux .Vars (r )
27
- alertID , err := base64 .URLEncoding .DecodeString (vars ["alertID" ])
38
+ func alertCtx (next http.Handler ) http.Handler {
39
+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
40
+ alertID , err := base64 .URLEncoding .DecodeString (chi .URLParam (r , "alertID" ))
28
41
if err != nil {
29
- if err != nil {
30
- http .Error (w , err .Error (), http .StatusInternalServerError )
31
- return
32
- }
42
+ http .Error (w , "" , http .StatusInternalServerError )
43
+ return
33
44
}
34
- switch r .Method {
35
- case "GET" :
36
- w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
37
- w .Write (db .getAlert (string (alertID )))
45
+ ctx := context .WithValue (r .Context (), "alertID" , string (alertID ))
46
+ next .ServeHTTP (w , r .WithContext (ctx ))
47
+ })
48
+ }
49
+
50
+ func getAlert (db store ) func (w http.ResponseWriter , r * http.Request ) {
51
+ return func (w http.ResponseWriter , r * http.Request ) {
52
+ ctx := r .Context ()
53
+ alertID , ok := ctx .Value ("alertID" ).(string )
54
+ l := xlog .FromRequest (r )
55
+ if ! ok {
56
+ http .Error (w , http .StatusText (422 ), 422 )
38
57
return
58
+ }
59
+ l .SetField ("message" , "Successfully returned alert: " + alertID )
60
+ w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
61
+ w .Write (db .getAlert (string (alertID )))
62
+ }
63
+ }
39
64
40
- case "POST" :
41
- decoder := json .NewDecoder (r .Body )
42
- var alert alertData
43
- err := decoder .Decode (& alert )
44
- if err != nil {
45
- http .Error (w , err .Error (), http .StatusInternalServerError )
46
- return
47
- }
48
- err = db .putAlert (alert )
49
- if err != nil {
50
- http .Error (w , err .Error (), http .StatusInternalServerError )
51
- return
52
- }
65
+ func deleteAlert (db store ) func (w http.ResponseWriter , r * http.Request ) {
66
+ return func (w http.ResponseWriter , r * http.Request ) {
67
+ ctx := r .Context ()
68
+ alertID , ok := ctx .Value ("alertID" ).(string )
69
+ if ! ok {
70
+ http .Error (w , http .StatusText (422 ), 422 )
71
+ return
72
+ }
53
73
74
+ data := db .getAlert (string (alertID ))
75
+ err := db .deleteAlert (string (alertID ))
76
+ l := xlog .FromRequest (r )
77
+ if err != nil {
78
+ l .Errorf ("Wasn't able to delete %s: %s" , alertID , err .Error ())
79
+ http .Error (w , err .Error (), http .StatusInternalServerError )
80
+ } else {
81
+ l .SetField ("message" , "Successfully deleted alert: " + alertID )
54
82
w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
55
- w .Header ().Set ("Location" , "/api/alert/" + base64 .URLEncoding .EncodeToString ([]byte (alert .ID )))
56
- w .WriteHeader (201 ) // Status 201 -- created
57
- w .Write (db .getAlert (alert .ID ))
58
- return
83
+ w .Write (data )
84
+ }
85
+ return
86
+ }
87
+ }
59
88
60
- case "DELETE" :
61
- data := db . getAlert ( string ( alertID ))
62
- err := db . deleteAlert ( string ( alertID ) )
63
- if err != nil {
64
- http . Error ( w , err . Error (), http . StatusInternalServerError )
65
- } else {
66
- w . Header (). Set ( "Content-Type" , "application/json; charset=utf-8" )
67
- w . Write ( data )
68
- }
89
+ func postAlert ( db store ) func ( w http. ResponseWriter , r * http. Request ) {
90
+ return func ( w http. ResponseWriter , r * http. Request ) {
91
+ decoder := json . NewDecoder ( r . Body )
92
+ var alert alertData
93
+ err := decoder . Decode ( & alert )
94
+ l := xlog . FromRequest ( r )
95
+ if err != nil {
96
+ l . Error ( "Wasn't able to decode the message body: " + err . Error () )
97
+ http . Error ( w , err . Error (), http . StatusInternalServerError )
69
98
return
70
-
71
- default :
72
- http .Error (w , "Method not allowed" , 405 )
99
+ }
100
+ err = db .putAlert (alert )
101
+ if err != nil {
102
+ l .Error ("Wasn't able to save the alert: " + err .Error ())
103
+ http .Error (w , err .Error (), http .StatusInternalServerError )
73
104
return
74
105
}
106
+ l .SetField ("message" , "Successfully created alert: " + alert .ID )
107
+ w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
108
+ w .Header ().Set ("Location" , "/api/alert/" + base64 .URLEncoding .EncodeToString ([]byte (alert .ID )))
109
+ w .WriteHeader (201 ) // Status 201 -- created
110
+ w .Write (db .getAlert (alert .ID ))
111
+ return
75
112
}
76
113
}
77
114
78
- func alertListHandler (db store ) func (w http.ResponseWriter , r * http.Request ) {
115
+ func listAlerts (db store ) func (w http.ResponseWriter , r * http.Request ) {
79
116
return func (w http.ResponseWriter , r * http.Request ) {
80
- vars := mux . Vars ( r )
81
- prefix := vars [ " prefix" ]
82
- data , err := db . getAlertsByPrefix ( prefix )
117
+ prefix := chi . URLParam ( r , "prefix" )
118
+ data , num , err := db . getAlertsByPrefix ( prefix )
119
+ l := xlog . FromRequest ( r )
83
120
if err != nil {
121
+ l .Error ("Wasn't able to get alerts: " + err .Error ())
84
122
http .Error (w , err .Error (), http .StatusInternalServerError )
85
123
} else {
124
+ l .SetField ("message" , fmt .Sprintf ("Successfully returned %d alerts" , num ))
86
125
w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
87
126
w .Write (data )
88
127
}
@@ -91,6 +130,8 @@ func alertListHandler(db store) func(w http.ResponseWriter, r *http.Request) {
91
130
92
131
func boltBackupHandler (db store ) func (w http.ResponseWriter , r * http.Request ) {
93
132
return func (w http.ResponseWriter , r * http.Request ) {
133
+ l := xlog .FromRequest (r )
94
134
db .backup (w )
135
+ l .SetField ("message" , "Database backup started" )
95
136
}
96
137
}
0 commit comments