-
-
Save stevenferrer/2a22f555bcf54d923d26190deb42f259 to your computer and use it in GitHub Desktop.
Revisions
-
Hunsin revised this gist
Sep 9, 2020 . 2 changed files with 85 additions and 105 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,106 +1,105 @@ package router import ( "context" "net/http" gpath "path" "github.com/julienschmidt/httprouter" ) // Param returns the named URL parameter from a request context. func Param(ctx context.Context, name string) string { if p := httprouter.ParamsFromContext(ctx); p != nil { return p.ByName(name) } return "" } // A Middleware chains http.Handlers. type Middleware func(http.Handler) http.Handler // A Router is a http.Handler which supports routing and middlewares. type Router struct { middlewares []Middleware path string root *httprouter.Router } // New creates a new Router. func New() *Router { return &Router{root: httprouter.New(), path: "/"} } // Group returns a new Router with given path and middlewares. // It should be used for handlers which have same path prefix or // common middlewares. func (r *Router) Group(path string, m ...Middleware) *Router { return &Router{ middlewares: append(m, r.middlewares...), path: gpath.Join(r.path, path), root: r.root, } } // Use appends new middlewares to current Router. func (r *Router) Use(m ...Middleware) *Router { r.middlewares = append(m, r.middlewares...) return r } // Handle registers a new request handler combined with middlewares. func (r *Router) Handle(method, path string, handler http.Handler) { for _, v := range r.middlewares { handler = v(handler) } r.root.Handler(method, gpath.Join(r.path, path), handler) } // GET is a shortcut for r.Handle("GET", path, handler) func (r *Router) GET(path string, handler http.HandlerFunc) { r.Handle(http.MethodGet, path, handler) } // HEAD is a shortcut for r.Handle("HEAD", path, handler) func (r *Router) HEAD(path string, handler http.HandlerFunc) { r.Handle(http.MethodHead, path, handler) } // OPTIONS is a shortcut for r.Handle("OPTIONS", path, handler) func (r *Router) OPTIONS(path string, handler http.HandlerFunc) { r.Handle(http.MethodOptions, path, handler) } // POST is a shortcut for r.Handle("POST", path, handler) func (r *Router) POST(path string, handler http.HandlerFunc) { r.Handle(http.MethodPost, path, handler) } // PUT is a shortcut for r.Handle("PUT", path, handler) func (r *Router) PUT(path string, handler http.HandlerFunc) { r.Handle(http.MethodPut, path, handler) } // PATCH is a shortcut for r.Handle("PATCH", path, handler) func (r *Router) PATCH(path string, handler http.HandlerFunc) { r.Handle(http.MethodPatch, path, handler) } // DELETE is a shortcut for r.Handle("DELETE", path, handler) func (r *Router) DELETE(path string, handler http.HandlerFunc) { r.Handle(http.MethodDelete, path, handler) } // HandleFunc is an adapter for http.HandlerFunc. func (r *Router) HandleFunc(method, path string, handler http.HandlerFunc) { r.Handle(method, path, handler) } // NotFound sets the handler which is called if the request path doesn't match // any routes. It overwrites the previous setting. func (r *Router) NotFound(handler http.Handler) { r.root.NotFound = handler } // Static serves files from given root directory. @@ -109,19 +108,19 @@ func (r *Router) Static(path, root string) { panic("path should end with '/*filepath' in path '" + path + "'.") } base := gpath.Join(r.path, path[:len(path)-9]) fileServer := http.StripPrefix(base, http.FileServer(http.Dir(root))) r.Handle(http.MethodGet, path, fileServer) } // File serves the named file. func (r *Router) File(path, name string) { r.HandleFunc(http.MethodGet, path, func(w http.ResponseWriter, req *http.Request) { http.ServeFile(w, req, name) }) } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.root.ServeHTTP(w, req) } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,17 +6,15 @@ import ( "net/http/httptest" "os" "testing" ) func TestHandle(t *testing.T) { router := New() h := func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) } router.Handle("GET", "/", http.HandlerFunc(h)) r := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() @@ -27,30 +25,13 @@ func TestHandle(t *testing.T) { } } func TestHandleFunc(t *testing.T) { router := New() h := func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) } router.HandleFunc("GET", "/", h) r := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() @@ -64,31 +45,31 @@ func TestHandlerFunc(t *testing.T) { func TestMethod(t *testing.T) { router := New() router.DELETE("/delete", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.GET("/get", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.HEAD("/head", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.OPTIONS("/options", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.PATCH("/patch", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.POST("/post", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.PUT("/put", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) @@ -118,19 +99,19 @@ func TestGroup(t *testing.T) { bar := router.Group("/bar") baz := foo.Group("/baz") foo.HandleFunc("GET", "", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) foo.HandleFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) bar.HandleFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) baz.HandleFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) @@ -150,21 +131,21 @@ func TestGroup(t *testing.T) { func TestMiddleware(t *testing.T) { var use, group bool router := New().Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { use = true next.ServeHTTP(w, r) }) }) foo := router.Group("/foo", func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { group = true next.ServeHTTP(w, r) }) }) foo.HandleFunc("GET", "/bar", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) -
Hunsin revised this gist
Jan 5, 2018 . No changes.There are no files selected for viewing
-
Hunsin revised this gist
Jan 5, 2018 . 2 changed files with 10 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,8 +15,8 @@ type Router struct { router *httprouter.Router } // New returns *Router with a new initialized *httprouter.Router embedded. func New() *Router { return &Router{router: httprouter.New()} } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,7 +11,7 @@ import ( ) func TestHandle(t *testing.T) { router := New() h := func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) @@ -28,7 +28,7 @@ func TestHandle(t *testing.T) { } func TestHandler(t *testing.T) { router := New() h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) @@ -45,7 +45,7 @@ func TestHandler(t *testing.T) { } func TestHandlerFunc(t *testing.T) { router := New() h := func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) @@ -62,7 +62,7 @@ func TestHandlerFunc(t *testing.T) { } func TestMethod(t *testing.T) { router := New() router.DELETE("/delete", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) @@ -113,7 +113,7 @@ func TestMethod(t *testing.T) { } func TestGroup(t *testing.T) { router := New() foo := router.Group("/foo") bar := router.Group("/bar") baz := foo.Group("/baz") @@ -150,7 +150,7 @@ func TestGroup(t *testing.T) { func TestMiddleware(t *testing.T) { var use, group bool router := New().Use(func(next httprouter.Handle) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { use = true next(w, r, ps) @@ -194,7 +194,7 @@ func TestStatic(t *testing.T) { } pwd, _ := os.Getwd() router := New() router.Static("/*filepath", pwd) for i := range files { @@ -222,7 +222,7 @@ func TestFile(t *testing.T) { f.Sync() f.Close() router := New() router.File("/file", "temp_file") r := httptest.NewRequest("GET", "/file", nil) -
Hunsin revised this gist
Dec 15, 2017 . No changes.There are no files selected for viewing
-
Hunsin revised this gist
Dec 15, 2017 . 1 changed file with 239 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,239 @@ package router import ( "io/ioutil" "net/http" "net/http/httptest" "os" "testing" "github.com/julienschmidt/httprouter" ) func TestHandle(t *testing.T) { router := NewRouter() h := func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) } router.Handle("GET", "/", h) r := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if w.Code != http.StatusTeapot { t.Error("Test Handle failed") } } func TestHandler(t *testing.T) { router := NewRouter() h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) router.Handler("GET", "/", h) r := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if w.Code != http.StatusTeapot { t.Error("Test Handler failed") } } func TestHandlerFunc(t *testing.T) { router := NewRouter() h := func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) } router.HandlerFunc("GET", "/", h) r := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if w.Code != http.StatusTeapot { t.Error("Test HandlerFunc failed") } } func TestMethod(t *testing.T) { router := NewRouter() router.DELETE("/delete", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.GET("/get", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.HEAD("/head", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.OPTIONS("/options", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.PATCH("/patch", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.POST("/post", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) router.PUT("/put", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusTeapot) }) samples := map[string]string{ "DELETE": "/delete", "GET": "/get", "HEAD": "/head", "OPTIONS": "/options", "PATCH": "/patch", "POST": "/post", "PUT": "/put", } for method, path := range samples { r := httptest.NewRequest(method, path, nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if w.Code != http.StatusTeapot { t.Errorf("Path %s not registered", path) } } } func TestGroup(t *testing.T) { router := NewRouter() foo := router.Group("/foo") bar := router.Group("/bar") baz := foo.Group("/baz") foo.HandlerFunc("GET", "", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) foo.HandlerFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) bar.HandlerFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) baz.HandlerFunc("GET", "/group", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) samples := []string{"/foo", "/foo/group", "/foo/baz/group", "/bar/group"} for _, path := range samples { r := httptest.NewRequest("GET", path, nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if w.Code != http.StatusTeapot { t.Errorf("Grouped path %s not registered", path) } } } func TestMiddleware(t *testing.T) { var use, group bool router := NewRouter().Use(func(next httprouter.Handle) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { use = true next(w, r, ps) } }) foo := router.Group("/foo", func(next httprouter.Handle) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { group = true next(w, r, ps) } }) foo.HandlerFunc("GET", "/bar", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusTeapot) }) r := httptest.NewRequest("GET", "/foo/bar", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) if !use { t.Error("Middleware registered by Use() under \"/\" not touched") } if !group { t.Error("Middleware registered by Group() under \"/foo\" not touched") } } func TestStatic(t *testing.T) { files := []string{"temp_1", "temp_2"} strs := []string{"test content", "static contents"} for i := range files { f, _ := os.Create(files[i]) defer os.Remove(files[i]) f.WriteString(strs[i]) f.Sync() f.Close() } pwd, _ := os.Getwd() router := NewRouter() router.Static("/*filepath", pwd) for i := range files { r := httptest.NewRequest("GET", "/"+files[i], nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) body := w.Result().Body defer body.Close() file, _ := ioutil.ReadAll(body) if string(file) != strs[i] { t.Error("Test Static failed") } } } func TestFile(t *testing.T) { str := "test_content" f, _ := os.Create("temp_file") defer os.Remove("temp_file") f.WriteString(str) f.Sync() f.Close() router := NewRouter() router.File("/file", "temp_file") r := httptest.NewRequest("GET", "/file", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) body := w.Result().Body defer body.Close() file, _ := ioutil.ReadAll(body) if string(file) != str { t.Error("Test File failed") } } -
Hunsin revised this gist
Dec 15, 2017 . 1 changed file with 33 additions and 32 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,102 +8,103 @@ import ( type middleware func(httprouter.Handle) httprouter.Handle // Router is a http.Handler that wraps httprouter.Router with additional features. type Router struct { middlewares []middleware path string router *httprouter.Router } // NewRouter returns *Router with a new initialized *httprouter.Router embedded. func NewRouter() *Router { return &Router{router: httprouter.New()} } func (r *Router) joinPath(path string) string { if (r.path + path)[0] != '/' { panic("path should start with '/' in path '" + path + "'.") } return r.path + path } // Group returns new *Router with given path and middlewares. // It should be used for handles which have same path prefix or common middlewares. func (r *Router) Group(path string, m ...middleware) *Router { if path[len(path)-1] == '/' { path = path[:len(path)-1] } return &Router{ middlewares: append(m, r.middlewares...), path: r.joinPath(path), router: r.router, } } // Use appends new middleware to current Router. func (r *Router) Use(m ...middleware) *Router { r.middlewares = append(m, r.middlewares...) return r } // Handle registers a new request handle combined with middlewares. func (r *Router) Handle(method, path string, handle httprouter.Handle) { for _, v := range r.middlewares { handle = v(handle) } r.router.Handle(method, r.joinPath(path), handle) } // GET is a shortcut for Router.Handle("GET", path, handle) func (r *Router) GET(path string, handle httprouter.Handle) { r.Handle("GET", path, handle) } // HEAD is a shortcut for Router.Handle("HEAD", path, handle) func (r *Router) HEAD(path string, handle httprouter.Handle) { r.Handle("HEAD", path, handle) } // OPTIONS is a shortcut for Router.Handle("OPTIONS", path, handle) func (r *Router) OPTIONS(path string, handle httprouter.Handle) { r.Handle("OPTIONS", path, handle) } // POST is a shortcut for Router.Handle("POST", path, handle) func (r *Router) POST(path string, handle httprouter.Handle) { r.Handle("POST", path, handle) } // PUT is a shortcut for Router.Handle("PUT", path, handle) func (r *Router) PUT(path string, handle httprouter.Handle) { r.Handle("PUT", path, handle) } // PATCH is a shortcut for Router.Handle("PATCH", path, handle) func (r *Router) PATCH(path string, handle httprouter.Handle) { r.Handle("PATCH", path, handle) } // DELETE is a shortcut for Router.Handle("DELETE", path, handle) func (r *Router) DELETE(path string, handle httprouter.Handle) { r.Handle("DELETE", path, handle) } // Handler is an adapter for http.Handler. func (r *Router) Handler(method, path string, handler http.Handler) { handle := func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) { handler.ServeHTTP(w, req) } r.Handle(method, path, handle) } // HandlerFunc is an adapter for http.HandlerFunc. func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) { r.Handler(method, path, handler) } // Static serves files from given root directory. func (r *Router) Static(path, root string) { if len(path) < 10 || path[len(path)-10:] != "/*filepath" { panic("path should end with '/*filepath' in path '" + path + "'.") } @@ -115,12 +116,12 @@ func (r *IRouter) Static(path, root string) { } // File serves the named file. func (r *Router) File(path, name string) { r.HandlerFunc("GET", path, func(w http.ResponseWriter, req *http.Request) { http.ServeFile(w, req, name) }) } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.router.ServeHTTP(w, req) } -
Hunsin revised this gist
Jul 5, 2017 . No changes.There are no files selected for viewing
-
Hunsin created this gist
Jul 4, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,126 @@ package router import ( "net/http" "github.com/julienschmidt/httprouter" ) type middleware func(httprouter.Handle) httprouter.Handle // IRouter is a http.Handler that wraps httprouter.Router with additional features. type IRouter struct { middlewares []middleware path string router *httprouter.Router } // NewRouter returns *IRouter with a new initialized httprouter.Router attached. func NewRouter() *IRouter { return &IRouter{router: httprouter.New()} } func (r *IRouter) joinPath(path string) string { if (r.path + path)[0] != '/' { panic("path should start with '/' in path '" + path + "'.") } return r.path + path } // Group returns new *IRouter with given path and middlewares. // It should be used for handles which have same path prefix or common middlewares. func (r *IRouter) Group(path string, m ...middleware) *IRouter { if path[len(path)-1] == '/' { path = path[:len(path)-1] } return &IRouter{ middlewares: append(m, r.middlewares...), path: r.joinPath(path), router: r.router, } } // Use appends new middleware to current IRouter. func (r *IRouter) Use(m ...middleware) { r.middlewares = append(m, r.middlewares...) } // Handle registers a new request handle combined with middlewares. func (r *IRouter) Handle(method, path string, handle httprouter.Handle) { for _, v := range r.middlewares { handle = v(handle) } r.router.Handle(method, r.joinPath(path), handle) } // GET is a shortcut for IRouter.Handle("GET", path, handle) func (r *IRouter) GET(path string, handle httprouter.Handle) { r.Handle("GET", path, handle) } // HEAD is a shortcut for IRouter.Handle("HEAD", path, handle) func (r *IRouter) HEAD(path string, handle httprouter.Handle) { r.Handle("HEAD", path, handle) } // OPTIONS is a shortcut for IRouter.Handle("OPTIONS", path, handle) func (r *IRouter) OPTIONS(path string, handle httprouter.Handle) { r.Handle("OPTIONS", path, handle) } // POST is a shortcut for IRouter.Handle("POST", path, handle) func (r *IRouter) POST(path string, handle httprouter.Handle) { r.Handle("POST", path, handle) } // PUT is a shortcut for IRouter.Handle("PUT", path, handle) func (r *IRouter) PUT(path string, handle httprouter.Handle) { r.Handle("PUT", path, handle) } // PATCH is a shortcut for IRouter.Handle("PATCH", path, handle) func (r *IRouter) PATCH(path string, handle httprouter.Handle) { r.Handle("PATCH", path, handle) } // DELETE is a shortcut for IRouter.Handle("DELETE", path, handle) func (r *IRouter) DELETE(path string, handle httprouter.Handle) { r.Handle("DELETE", path, handle) } // Handler is an adapter for http.Handler. func (r *IRouter) Handler(method, path string, handler http.Handler) { handle := func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) { handler.ServeHTTP(w, req) } r.Handle(method, path, handle) } // HandlerFunc is an adapter for http.HandlerFunc. func (r *IRouter) HandlerFunc(method, path string, handler http.HandlerFunc) { r.Handler(method, path, handler) } // Static serves files from given root directory. func (r *IRouter) Static(path, root string) { if len(path) < 10 || path[len(path)-10:] != "/*filepath" { panic("path should end with '/*filepath' in path '" + path + "'.") } base := r.joinPath(path[:len(path)-9]) fileServer := http.StripPrefix(base, http.FileServer(http.Dir(root))) r.Handler("GET", path, fileServer) } // File serves the named file. func (r *IRouter) File(path, name string) { r.HandlerFunc("GET", path, func(w http.ResponseWriter, req *http.Request) { http.ServeFile(w, req, name) }) } func (r *IRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.router.ServeHTTP(w, req) }