Add middleware

This commit is contained in:
Nise Void 2018-10-09 18:07:43 +02:00
parent 5a44e82541
commit 69754a9946
Signed by: NiseVoid
GPG Key ID: FBA14AC83EA602F3
3 changed files with 127 additions and 65 deletions

18
default.go Normal file
View File

@ -0,0 +1,18 @@
package router
import (
"fmt"
)
func defaultNotFoundHandler(c *Context) error {
return c.String(404, `not found`)
}
func defaultMethodNotAllowedHandler(c *Context) error {
return c.String(504, `method not allowed`)
}
func defaultErrorHandler(c *Context, err interface{}) {
fmt.Println(err)
c.String(500, `internal server error`)
}

View File

@ -6,48 +6,49 @@ func join(prefix, path string) string {
return urlpath.Join(prefix, urlpath.Clean(path)) return urlpath.Join(prefix, urlpath.Clean(path))
} }
// Group is a router group with a shared prefix and set of middlewares
type Group struct { type Group struct {
router *Router router *Router
prefix string prefix string
middleware []Middleware
} }
func (g *Group) Group(prefix string) *Group { // Group creates a new router group with a shared prefix and set of middlewares
return &Group{prefix: join(g.prefix, prefix), router: g.router} func (g *Group) Group(prefix string, middleware ...Middleware) *Group {
return &Group{prefix: join(g.prefix, prefix), router: g.router, middleware: append(g.middleware, middleware...)}
} }
// GET adds a GET route // GET adds a GET route
func (g *Group) GET(path string, handle GetHandle) { func (g *Group) GET(path string, handle Handle, middleware ...Middleware) {
g.router.GET(join(g.prefix, path), handle) g.router.GET(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
} }
// POST adds a POST route // POST adds a POST route
func (g *Group) POST(path string, handle interface{}) { func (g *Group) POST(path string, handle interface{}, middleware ...Middleware) {
g.router.POST(join(g.prefix, path), handle) g.router.POST(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
} }
// DELETE adds a DELETE route // DELETE adds a DELETE route
func (g *Group) DELETE(path string, handle GetHandle) { func (g *Group) DELETE(path string, handle Handle, middleware ...Middleware) {
g.router.DELETE(join(g.prefix, path), handle) g.router.DELETE(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
} }
// PUT adds a PUT route // PUT adds a PUT route
func (g *Group) PUT(path string, handle interface{}) { func (g *Group) PUT(path string, handle interface{}, middleware ...Middleware) {
checkInterfaceHandle(handle) g.router.PUT(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
g.router.PUT(join(g.prefix, path), handle)
} }
// PATCH adds a PATCH route // PATCH adds a PATCH route
func (g *Group) PATCH(path string, handle interface{}) { func (g *Group) PATCH(path string, handle interface{}, middleware ...Middleware) {
checkInterfaceHandle(handle) g.router.PATCH(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
g.router.PATCH(join(g.prefix, path), handle)
} }
// HEAD adds a HEAD route // HEAD adds a HEAD route
func (g *Group) HEAD(path string, handle GetHandle) { func (g *Group) HEAD(path string, handle Handle, middleware ...Middleware) {
g.router.HEAD(join(g.prefix, path), handle) g.router.HEAD(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
} }
// OPTIONS adds a OPTIONS route // OPTIONS adds a OPTIONS route
func (g *Group) OPTIONS(path string, handle GetHandle) { func (g *Group) OPTIONS(path string, handle Handle, middleware ...Middleware) {
g.router.OPTIONS(join(g.prefix, path), handle) g.router.OPTIONS(join(g.prefix, path), handle, append(g.middleware, middleware...)...)
} }

119
router.go
View File

@ -2,7 +2,6 @@ package router
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"reflect" "reflect"
@ -13,62 +12,79 @@ type route struct {
Method string Method string
Path string Path string
Handle interface{} Handle interface{}
Middleware []Middleware
} }
// GetHandle handles a request that doesn't receive a body // Handle handles a request
type GetHandle func(*Context) error type Handle func(*Context) error
// ErrorHandle handles a request
type ErrorHandle func(*Context, interface{})
// Middleware TODO:
type Middleware func(Handle) Handle
// Router is the router itself // Router is the router itself
type Router struct { type Router struct {
routes []route routes []route
Renderer Renderer Renderer Renderer
middleware []Middleware
NotFoundHandler Handle
MethodNotAllowedHandler Handle
ErrorHandler ErrorHandle
} }
// New returns a new Router // New returns a new Router
func New() *Router { func New() *Router {
return &Router{} return &Router{NotFoundHandler: defaultNotFoundHandler, MethodNotAllowedHandler: defaultMethodNotAllowedHandler, ErrorHandler: defaultErrorHandler}
} }
func (r *Router) Group(prefix string) *Group { // Use adds a global middleware
return &Group{prefix: prefix, router: r} func (r *Router) Use(m ...Middleware) {
r.middleware = append(r.middleware, m...)
}
// Group creates a new router group with a shared prefix and set of middlewares
func (r *Router) Group(prefix string, middleware ...Middleware) *Group {
return &Group{prefix: prefix, router: r, middleware: middleware}
} }
// GET adds a GET route // GET adds a GET route
func (r *Router) GET(path string, handle GetHandle) { func (r *Router) GET(path string, handle Handle, middleware ...Middleware) {
r.routes = append(r.routes, route{`GET`, path, handle}) r.routes = append(r.routes, route{`GET`, path, handle, middleware})
} }
// POST adds a POST route // POST adds a POST route
func (r *Router) POST(path string, handle interface{}) { func (r *Router) POST(path string, handle interface{}, middleware ...Middleware) {
checkInterfaceHandle(handle) checkInterfaceHandle(handle)
r.routes = append(r.routes, route{`POST`, path, handle}) r.routes = append(r.routes, route{`POST`, path, handle, middleware})
} }
// DELETE adds a DELETE route // DELETE adds a DELETE route
func (r *Router) DELETE(path string, handle GetHandle) { func (r *Router) DELETE(path string, handle Handle, middleware ...Middleware) {
r.routes = append(r.routes, route{`DELETE`, path, handle}) r.routes = append(r.routes, route{`DELETE`, path, handle, middleware})
} }
// PUT adds a PUT route // PUT adds a PUT route
func (r *Router) PUT(path string, handle interface{}) { func (r *Router) PUT(path string, handle interface{}, middleware ...Middleware) {
checkInterfaceHandle(handle) checkInterfaceHandle(handle)
r.routes = append(r.routes, route{`PUT`, path, handle}) r.routes = append(r.routes, route{`PUT`, path, handle, middleware})
} }
// PATCH adds a PATCH route // PATCH adds a PATCH route
func (r *Router) PATCH(path string, handle interface{}) { func (r *Router) PATCH(path string, handle interface{}, middleware ...Middleware) {
checkInterfaceHandle(handle) checkInterfaceHandle(handle)
r.routes = append(r.routes, route{`PATCH`, path, handle}) r.routes = append(r.routes, route{`PATCH`, path, handle, middleware})
} }
// HEAD adds a HEAD route // HEAD adds a HEAD route
func (r *Router) HEAD(path string, handle GetHandle) { func (r *Router) HEAD(path string, handle Handle, middleware ...Middleware) {
r.routes = append(r.routes, route{`HEAD`, path, handle}) r.routes = append(r.routes, route{`HEAD`, path, handle, middleware})
} }
// OPTIONS adds a OPTIONS route // OPTIONS adds a OPTIONS route
func (r *Router) OPTIONS(path string, handle GetHandle) { func (r *Router) OPTIONS(path string, handle Handle, middleware ...Middleware) {
r.routes = append(r.routes, route{`OPTIONS`, path, handle}) r.routes = append(r.routes, route{`OPTIONS`, path, handle, middleware})
} }
// Start starts the web server and binds to the given address // Start starts the web server and binds to the given address
@ -82,19 +98,39 @@ func (r *Router) getHttpr() *httprouter.Router {
httpr := httprouter.New() httpr := httprouter.New()
for _, v := range r.routes { for _, v := range r.routes {
if handle, ok := v.Handle.(GetHandle); ok { handle, ok := v.Handle.(Handle)
httpr.Handle(v.Method, v.Path, handleGET(r, handle)) if !ok {
continue handle = handlePOST(r, v.Handle)
} }
httpr.Handle(v.Method, v.Path, handlePOST(r, v.Handle)) httpr.Handle(v.Method, v.Path, handleReq(r, handle, append(r.middleware, v.Middleware...)))
}
httpr.NotFound = http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
handleReq(r, r.NotFoundHandler, r.middleware)(res, req, nil)
})
httpr.MethodNotAllowed = http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
handleReq(r, r.MethodNotAllowedHandler, r.middleware)(res, req, nil)
})
httpr.PanicHandler = func(res http.ResponseWriter, req *http.Request, err interface{}) {
c := newContext(r, res, req, nil)
r.ErrorHandler(c, err)
} }
return httpr return httpr
} }
func handleErr(errHandler ErrorHandle, err interface{}) Handle {
return func(c *Context) error {
errHandler(c, err)
return nil
}
}
func checkInterfaceHandle(f interface{}) { func checkInterfaceHandle(f interface{}) {
if _, ok := f.(GetHandle); ok { if _, ok := f.(Handle); ok {
return return
} }
@ -119,34 +155,41 @@ func checkInterfaceHandle(f interface{}) {
return return
} }
func handlePOST(r *Router, f interface{}) httprouter.Handle { func handlePOST(r *Router, f interface{}) Handle {
funcRv, inputRt := reflect.ValueOf(f), reflect.TypeOf(f).In(1) funcRv, inputRt := reflect.ValueOf(f), reflect.TypeOf(f).In(1)
return func(res http.ResponseWriter, req *http.Request, param httprouter.Params) { return func(c *Context) error {
c := newContext(r, res, req, param)
data := reflect.New(inputRt) data := reflect.New(inputRt)
{
err := json.NewDecoder(req.Body).Decode(data.Interface()) err := json.NewDecoder(c.Request.Body).Decode(data.Interface())
req.Body.Close() c.Request.Body.Close()
if err != nil { if err != nil {
c.NoContent(400) // TODO: send info about error (BindError) c.NoContent(400) // TODO: send info about error (BindError)
return return nil
}
} }
out := funcRv.Call([]reflect.Value{reflect.ValueOf(c), data.Elem()}) out := funcRv.Call([]reflect.Value{reflect.ValueOf(c), data.Elem()})
err := out[0].Interface()
_ = err if out[0].IsNil() {
return nil
}
return out[0].Interface().(error)
} }
} }
func handleGET(r *Router, f GetHandle) httprouter.Handle { func handleReq(r *Router, handle Handle, m []Middleware) httprouter.Handle {
return func(res http.ResponseWriter, req *http.Request, param httprouter.Params) { return func(res http.ResponseWriter, req *http.Request, param httprouter.Params) {
c := newContext(r, res, req, param) c := newContext(r, res, req, param)
f := handle
for i := len(m) - 1; i >= 0; i-- { // TODO: 1,2,3 of 3,2,1
f = m[i](f)
}
err := f(c) err := f(c)
fmt.Println(err) if err != nil {
r.ErrorHandler(c, err)
}
} }
} }