-
Notifications
You must be signed in to change notification settings - Fork 9
/
version.go
136 lines (120 loc) · 3.69 KB
/
version.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
package rest
import (
"encoding/json"
"runtime/debug"
"github.com/fasthttp/router"
"github.com/seventv/api/internal/api/rest/rest"
v2 "github.com/seventv/api/internal/api/rest/v2"
v3 "github.com/seventv/api/internal/api/rest/v3"
"github.com/seventv/api/internal/global"
"github.com/seventv/common/errors"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
func (s *HttpServer) V3(gCtx global.Context) {
s.traverseRoutes(v3.API(gCtx, s.router), s.router)
}
func (s *HttpServer) V2(gCtx global.Context) {
s.traverseRoutes(v2.API(gCtx, s.router), s.router)
}
func (s *HttpServer) SetupHandlers() {
// Handle Not Found
s.router.NotFound = s.getErrorHandler(
rest.NotFound,
errors.ErrUnknownRoute().SetFields(errors.Fields{
"message": "The API endpoint requested does not exist",
}),
)
// Handle P A N I C
s.router.PanicHandler = func(ctx *fasthttp.RequestCtx, i interface{}) {
err := "Uh oh. Something went horribly wrong"
switch x := i.(type) {
case error:
err += ": " + x.Error()
case string:
err += ": " + x
}
zap.S().Errorw("panic occured",
"panic", i,
"stack", debug.Stack(),
)
s.getErrorHandler(
rest.InternalServerError,
errors.ErrInternalServerError().SetFields(errors.Fields{
"panic": err,
}),
)(ctx)
}
}
func (s *HttpServer) traverseRoutes(r rest.Route, parentGroup Router) {
c := r.Config()
// Compose the full request URI (prefixing with parent, if any)
routable := parentGroup
group := routable.Group(c.URI)
l := zap.S().With(
"group", group,
"method", c.Method,
)
// Handle requests
group.Handle(string(c.Method), "", func(ctx *fasthttp.RequestCtx) {
rctx := &rest.Ctx{RequestCtx: ctx}
handlers := make([]rest.Middleware, len(c.Middleware)+1)
copy(handlers, c.Middleware)
handlers[len(handlers)-1] = r.Handler
for _, h := range handlers {
if err := h(rctx); err != nil {
// If the request handler returned an error
// we will format it into standard API error response
if ctx.Response.StatusCode() < 400 {
rctx.SetStatusCode(rest.HttpStatusCode(err.ExpectedHTTPStatus()))
}
resp := &rest.APIErrorResponse{
Status: rctx.StatusCode().String(),
StatusCode: rctx.StatusCode(),
Error: err.Message(),
ErrorCode: err.Code(),
Details: err.GetFields(),
}
b, _ := json.Marshal(resp)
rctx.SetContentType("application/json")
rctx.SetBody(b)
return
}
}
})
l.Debug("Route registered")
// activate child routes
for _, child := range c.Children {
s.traverseRoutes(child, group)
}
}
func (s *HttpServer) getErrorHandler(status rest.HttpStatusCode, err rest.APIError) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) {
b, _ := json.Marshal(&rest.APIErrorResponse{
Status: status.String(),
StatusCode: status,
Error: err.Message(),
ErrorCode: err.Code(),
Details: err.GetFields(),
})
ctx.SetStatusCode(err.ExpectedHTTPStatus())
ctx.SetContentType("application/json")
ctx.SetBody(b)
}
}
type Router interface {
ANY(path string, handler fasthttp.RequestHandler)
CONNECT(path string, handler fasthttp.RequestHandler)
DELETE(path string, handler fasthttp.RequestHandler)
GET(path string, handler fasthttp.RequestHandler)
Group(path string) *router.Group
HEAD(path string, handler fasthttp.RequestHandler)
Handle(method, path string, handler fasthttp.RequestHandler)
OPTIONS(path string, handler fasthttp.RequestHandler)
PATCH(path string, handler fasthttp.RequestHandler)
POST(path string, handler fasthttp.RequestHandler)
PUT(path string, handler fasthttp.RequestHandler)
ServeFiles(path string, rootPath string)
ServeFilesCustom(path string, fs *fasthttp.FS)
TRACE(path string, handler fasthttp.RequestHandler)
}