130 lines
2.7 KiB
Go
130 lines
2.7 KiB
Go
|
package route
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"strings"
|
||
|
|
||
|
"sectorinf.com/emilis/fupie/logie"
|
||
|
)
|
||
|
|
||
|
type Method string
|
||
|
type Route struct {
|
||
|
Pattern PartPattern
|
||
|
Handler HandlerFunc
|
||
|
}
|
||
|
type Routes []Route
|
||
|
type Middleware func(http.Request, Keeper)
|
||
|
|
||
|
var (
|
||
|
NotFoundHandler = func(ctx Context) {
|
||
|
ctx.Status(http.StatusNotFound)
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func (r Routes) Match(path string) HandlerFunc {
|
||
|
for _, route := range r {
|
||
|
if route.Pattern.Match(path) {
|
||
|
return route.Handler
|
||
|
}
|
||
|
}
|
||
|
return NotFoundHandler
|
||
|
}
|
||
|
|
||
|
type HandlerFunc func(Context)
|
||
|
|
||
|
type Router struct {
|
||
|
fnMatcher map[Method]Routes
|
||
|
middleware []Middleware
|
||
|
logger logie.Log
|
||
|
}
|
||
|
|
||
|
func New(logger logie.Log) Router {
|
||
|
return Router{
|
||
|
fnMatcher: map[Method]Routes{
|
||
|
http.MethodGet: {},
|
||
|
http.MethodConnect: {},
|
||
|
http.MethodPatch: {},
|
||
|
http.MethodPost: {},
|
||
|
http.MethodPut: {},
|
||
|
http.MethodDelete: {},
|
||
|
http.MethodHead: {},
|
||
|
http.MethodOptions: {},
|
||
|
http.MethodTrace: {},
|
||
|
},
|
||
|
logger: logger,
|
||
|
middleware: []Middleware{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||
|
byMethod, exists := r.fnMatcher[Method(req.Method)]
|
||
|
if !exists {
|
||
|
w.WriteHeader(http.StatusNotFound)
|
||
|
return
|
||
|
}
|
||
|
fn := byMethod.Match(req.URL.Path)
|
||
|
rwk := &ResponseWriterKeeper{
|
||
|
ResponseWriter: w,
|
||
|
Keeper: Keeper{
|
||
|
// Default 200
|
||
|
Status: http.StatusOK,
|
||
|
},
|
||
|
}
|
||
|
fn(Context{
|
||
|
Request: req,
|
||
|
Writer: rwk,
|
||
|
Context: context.Background(),
|
||
|
Log: r.logger,
|
||
|
})
|
||
|
for _, mware := range r.middleware {
|
||
|
mware(*req, rwk.Keeper)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r Router) With(method, pathExpr string, handler HandlerFunc) Router {
|
||
|
r.fnMatcher[Method(method)] = append(r.fnMatcher[Method(method)], Route{
|
||
|
Pattern: Pattern(pathExpr),
|
||
|
Handler: handler,
|
||
|
})
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (r Router) GET(pathExpr string, handler HandlerFunc) Router {
|
||
|
return r.With(http.MethodGet, pathExpr, handler)
|
||
|
}
|
||
|
|
||
|
func (r Router) POST(pathExpr string, handler HandlerFunc) Router {
|
||
|
return r.With(http.MethodPost, pathExpr, handler)
|
||
|
}
|
||
|
|
||
|
func (r Router) PATCH(pathExpr string, handler HandlerFunc) Router {
|
||
|
return r.With(http.MethodPatch, pathExpr, handler)
|
||
|
}
|
||
|
|
||
|
func (r Router) PUT(pathExpr string, handler HandlerFunc) Router {
|
||
|
return r.With(http.MethodPut, pathExpr, handler)
|
||
|
}
|
||
|
|
||
|
func (r Router) DELETE(pathExpr string, handler HandlerFunc) Router {
|
||
|
return r.With(http.MethodDelete, pathExpr, handler)
|
||
|
}
|
||
|
|
||
|
func (r Router) Middleware(mware ...Middleware) Router {
|
||
|
r.middleware = mware
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (r Router) Group(prefix string, fn func(Router) Router) Router {
|
||
|
prefix = strings.TrimSuffix(prefix, "/")
|
||
|
group := fn(New(r.logger))
|
||
|
for method, byRoute := range group.fnMatcher {
|
||
|
for _, route := range byRoute {
|
||
|
r = r.With(string(method), fmt.Sprintf("%s/%s", prefix, route.Pattern.String()), route.Handler)
|
||
|
}
|
||
|
}
|
||
|
return r
|
||
|
}
|