package wisp import ( "context" "net/http" "strings" "github.com/julienschmidt/httprouter" ) type Wisp struct { router *httprouter.Router errorHandler ErrorHandler middlewares []Middleware } func New() *Wisp { return &Wisp{ router: httprouter.New(), errorHandler: defaultErrorHandler, middlewares: []Middleware{}, } } func (w *Wisp) SetErrorHandler(errorHandler ErrorHandler) { w.errorHandler = errorHandler } func (w *Wisp) Use(m ...Middleware) { w.middlewares = append(w.middlewares, m...) } func (w *Wisp) Group(prefix string, middlewares ...Middleware) *Group { return &Group{ prefix: prefix, parent: w, middlewares: middlewares, } } func (w *Wisp) GET(path string, h Handler, mws ...Middleware) { w.handle(http.MethodGet, path, h, mws...) } func (w *Wisp) POST(path string, h Handler, mws ...Middleware) { w.handle(http.MethodPost, path, h, mws...) } func (w *Wisp) PUT(path string, h Handler, mws ...Middleware) { w.handle(http.MethodPut, path, h, mws...) } func (w *Wisp) DELETE(path string, h Handler, mws ...Middleware) { w.handle(http.MethodDelete, path, h, mws...) } func (w *Wisp) PATCH(path string, h Handler, mws ...Middleware) { w.handle(http.MethodPatch, path, h, mws...) } func (w *Wisp) OPTIONS(path string, h Handler, mws ...Middleware) { w.handle(http.MethodOptions, path, h, mws...) } func (w *Wisp) HEAD(path string, h Handler, mws ...Middleware) { w.handle(http.MethodHead, path, h, mws...) } func (w *Wisp) Static(path, root string) { if !strings.HasSuffix(path, "/*filepath") { if strings.HasSuffix(path, "/") { path += "*filepath" } else { path += "/*filepath" } } fileServer := http.StripPrefix(strings.TrimSuffix(path, "/*filepath"), http.FileServer(http.Dir(root))) w.router.GET(path, func(wr http.ResponseWriter, r *http.Request, _ httprouter.Params) { fileServer.ServeHTTP(wr, r) }) } func (w *Wisp) Start(addr string) error { return http.ListenAndServe(addr, w.router) } func (w *Wisp) StartWithTLS(addr, certFile, keyFile string) error { return http.ListenAndServeTLS(addr, certFile, keyFile, w.router) } func (w *Wisp) handle(method, path string, h Handler, mws ...Middleware) { all := append(w.middlewares, mws...) final := w.chainMiddlewares(h, all) w.register(method, path, w.makeHTTPRouterHandler(final)) } func (w *Wisp) register(method, path string, h httprouter.Handle) { switch method { case http.MethodGet: w.router.GET(path, h) case http.MethodPost: w.router.POST(path, h) case http.MethodPut: w.router.PUT(path, h) case http.MethodDelete: w.router.DELETE(path, h) case http.MethodPatch: w.router.PATCH(path, h) case http.MethodOptions: w.router.OPTIONS(path, h) case http.MethodHead: w.router.HEAD(path, h) } } func (w *Wisp) chainMiddlewares(h Handler, mws []Middleware) Handler { for i := len(mws) - 1; i >= 0; i-- { h = mws[i](h) } return h } func (w *Wisp) makeHTTPRouterHandler(h Handler) httprouter.Handle { return func(wr http.ResponseWriter, r *http.Request, p httprouter.Params) { context := &Context{ response: wr, request: r, params: p, ctx: context.Background(), } if err := h(context); err != nil { w.errorHandler(err, context) } } }