From 5853c1003bf63f8d22e8e950f47c02ffd9bb1f76 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 25 Jun 2017 13:03:35 -0400 Subject: [PATCH 1/4] Correct group logic --- group.go | 6 ++--- group_test.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/group.go b/group.go index 1a68bb4..45aa650 100644 --- a/group.go +++ b/group.go @@ -187,7 +187,7 @@ func (g *routeGroup) Group(prefix string, middleware ...Handler) IRouteGroup { } if len(middleware) == 0 { - rg.middleware = make(HandlersChain, len(g.middleware)+len(middleware)) + rg.middleware = make(HandlersChain, len(g.middleware)) copy(rg.middleware, g.middleware) return rg @@ -198,8 +198,8 @@ func (g *routeGroup) Group(prefix string, middleware ...Handler) IRouteGroup { return rg } - rg.middleware = make(HandlersChain, len(g.lars.middleware)) - copy(rg.middleware, g.lars.middleware) + rg.middleware = make(HandlersChain, len(g.middleware)) + copy(rg.middleware, g.middleware) rg.Use(middleware...) return rg diff --git a/group_test.go b/group_test.go index 6858ef7..6d197cc 100644 --- a/group_test.go +++ b/group_test.go @@ -81,3 +81,65 @@ func TestWebsockets(t *testing.T) { Equal(t, wsBad, nil) Equal(t, res.StatusCode, http.StatusForbidden) } + +func TestGrouplogic(t *testing.T) { + + var aa, bb, cc, tl int + + aM := func(c Context) { + aa++ + c.Next() + } + + bM := func(c Context) { + bb++ + c.Next() + } + + cM := func(c Context) { + cc++ + c.Next() + } + + l := New() + l.Use(func(c Context) { + tl++ + c.Next() + }) + + a := l.Group("/a", aM) + a.Get("/test", func(c Context) { + c.JSON(http.StatusOK, "a-ok") + }) + + b := a.Group("/b", bM) + b.Get("/test", func(c Context) { + c.JSON(http.StatusOK, "b-ok") + }) + + c := b.Group("/c", cM) + c.Get("/test", func(c Context) { + c.JSON(http.StatusOK, "c-ok") + }) + + code, body := request(GET, "/a/test", l) + Equal(t, code, http.StatusOK) + Equal(t, body, "\"a-ok\"") + Equal(t, tl, 1) + Equal(t, aa, 1) + + code, body = request(GET, "/a/b/test", l) + Equal(t, code, http.StatusOK) + Equal(t, body, "\"b-ok\"") + Equal(t, tl, 2) + Equal(t, aa, 2) + Equal(t, bb, 1) + + code, body = request(GET, "/a/b/c/test", l) + Equal(t, code, http.StatusOK) + Equal(t, body, "\"c-ok\"") + Equal(t, tl, 3) + Equal(t, aa, 3) + Equal(t, bb, 2) + Equal(t, cc, 1) +} From b0c58b55aafe80e657c7079675071ff8dba8f4b1 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 25 Jun 2017 13:19:29 -0400 Subject: [PATCH 2/4] break up group function Group handled 3 separate pieces of logic, which have now been broken out for clarity and ease of use into: Group - groups retaining existing middleware GroupWithMore - groups retaining middleware and adding additional GroupWithNone - groups but retains no middleware --- README.md | 2 +- group.go | 47 ++++++++++++++++++++++++++--------------------- group_test.go | 6 +++--- lars_test.go | 4 ++-- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index df5d634..0d943b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## LARS -![Project status](https://img.shields.io/badge/version-3.7.0-green.svg) +![Project status](https://img.shields.io/badge/version-4.0.0-green.svg) [![Build Status](https://semaphoreci.com/api/v1/projects/4351aa2d-2f94-40be-a6ef-85c248490378/679708/badge.svg)](https://semaphoreci.com/joeybloggs/lars) [![Coverage Status](https://coveralls.io/repos/github/go-playground/lars/badge.svg?branch=master)](https://coveralls.io/github/go-playground/lars?branch=master) [![Go Report Card](https://goreportcard.com/badge/go-playground/lars)](https://goreportcard.com/report/go-playground/lars) diff --git a/group.go b/group.go index 45aa650..a577948 100644 --- a/group.go +++ b/group.go @@ -10,7 +10,9 @@ import ( // IRouteGroup interface for router group type IRouteGroup interface { IRoutes - Group(prefix string, middleware ...Handler) IRouteGroup + GroupWithNone(prefix string) IRouteGroup + GroupWithMore(prefix string, middleware ...Handler) IRouteGroup + Group(prefix string) IRouteGroup } // IRoutes interface for routes @@ -176,31 +178,34 @@ func (g *routeGroup) WebSocket(upgrader websocket.Upgrader, path string, h Handl }, handler) } -// Group creates a new sub router with prefix. It inherits all properties from -// the parent. Passing middleware overrides parent middleware but still keeps -// the root level middleware intact. -func (g *routeGroup) Group(prefix string, middleware ...Handler) IRouteGroup { - - rg := &routeGroup{ - prefix: g.prefix + prefix, - lars: g.lars, - } - - if len(middleware) == 0 { - rg.middleware = make(HandlersChain, len(g.middleware)) - copy(rg.middleware, g.middleware) - - return rg +// GroupWithNone creates a new sub router with specified prefix and no middleware attached. +func (g *routeGroup) GroupWithNone(prefix string) IRouteGroup { + return &routeGroup{ + prefix: g.prefix + prefix, + lars: g.lars, + middleware: make(HandlersChain, 0), } +} - if middleware[0] == nil { - rg.middleware = make(HandlersChain, 0) - return rg +// GroupWithMore creates a new sub router with specified prefix, retains existing middleware and adds new middleware. +func (g *routeGroup) GroupWithMore(prefix string, middleware ...Handler) IRouteGroup { + rg := &routeGroup{ + prefix: g.prefix + prefix, + lars: g.lars, + middleware: make(HandlersChain, len(g.middleware)), } - - rg.middleware = make(HandlersChain, len(g.middleware)) copy(rg.middleware, g.middleware) rg.Use(middleware...) + return rg +} +// Group creates a new sub router with specified prefix and retains existing middleware. +func (g *routeGroup) Group(prefix string) IRouteGroup { + rg := &routeGroup{ + prefix: g.prefix + prefix, + lars: g.lars, + middleware: make(HandlersChain, len(g.middleware)), + } + copy(rg.middleware, g.middleware) return rg } diff --git a/group_test.go b/group_test.go index 6d197cc..d3b7406 100644 --- a/group_test.go +++ b/group_test.go @@ -107,17 +107,17 @@ func TestGrouplogic(t *testing.T) { c.Next() }) - a := l.Group("/a", aM) + a := l.GroupWithMore("/a", aM) a.Get("/test", func(c Context) { c.JSON(http.StatusOK, "a-ok") }) - b := a.Group("/b", bM) + b := a.GroupWithMore("/b", bM) b.Get("/test", func(c Context) { c.JSON(http.StatusOK, "b-ok") }) - c := b.Group("/c", cM) + c := b.GroupWithMore("/c", cM) c.Get("/test", func(c Context) { c.JSON(http.StatusOK, "c-ok") }) diff --git a/lars_test.go b/lars_test.go index 3337501..b48bb5e 100644 --- a/lars_test.go +++ b/lars_test.go @@ -351,7 +351,7 @@ func TestUseAndGroup(t *testing.T) { c.Next() } - sh := l.Group("/superheros", logger2) + sh := l.GroupWithMore("/superheros", logger2) sh.Get("/", fn) sh.Get("/list/", fn) @@ -381,7 +381,7 @@ func TestUseAndGroup(t *testing.T) { log = "" - g2 := l.Group("/admins", nil) + g2 := l.GroupWithNone("/admins") g2.Get("/", fn) g2.Get("/list/", fn) From 967881de0b9aab9ebd6441e894038ded820189a3 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 25 Jun 2017 13:26:31 -0400 Subject: [PATCH 3/4] Update Group documentation --- README.md | 4 ++-- doc.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0d943b4..8c7fdaa 100644 --- a/README.md +++ b/README.md @@ -100,10 +100,10 @@ contactinfo.Delete("/delete", ...) // creates a group for others + inherits all middleware registered using l.Use() + adds // OtherHandler to middleware -others := l.Group("/others", OtherHandler) +others := l.GroupWithMore("/others", OtherHandler) // creates a group for admin WITH NO MIDDLEWARE... more can be added using admin.Use() -admin := l.Group("/admin",nil) +admin := l.GroupWithNone("/admin") admin.Use(SomeAdminSecurityMiddleware) ... ``` diff --git a/doc.go b/doc.go index 9dec7b1..6fa2886 100644 --- a/doc.go +++ b/doc.go @@ -73,10 +73,10 @@ example group definitions // creates a group for others + inherits all middleware registered using l.Use() + // adds OtherHandler to middleware - others := l.Group("/others", OtherHandler) + others := l.GroupWithMore("/others", OtherHandler) // creates a group for admin WITH NO MIDDLEWARE... more can be added using admin.Use() - admin := l.Group("/admin",nil) + admin := l.GroupWithNone("/admin") admin.Use(SomeAdminSecurityMiddleware) ... From 0f61e8592441bc689aa56e338b4b65e91d07c44f Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 25 Jun 2017 13:30:42 -0400 Subject: [PATCH 4/4] Updated examples DIR to _examples renamed to ensure example dependencies, if any, aren't fetched during go get --- README.md | 20 +++++++++--------- {examples => _examples}/README/test.gif | Bin {examples => _examples}/README/test.go | 0 {examples => _examples}/all-in-one/main.go | 0 .../custom-handler/main.go | 0 {examples => _examples}/decode/main.go | 0 {examples => _examples}/groups/main.go | 0 {examples => _examples}/hello-world/main.go | 2 +- .../logging-recovery/logging_recovery.go | 0 {examples => _examples}/native/main.go | 0 {examples => _examples}/websockets/main.go | 2 +- doc.go | 6 +++--- 12 files changed, 15 insertions(+), 15 deletions(-) rename {examples => _examples}/README/test.gif (100%) rename {examples => _examples}/README/test.go (100%) rename {examples => _examples}/all-in-one/main.go (100%) rename {examples => _examples}/custom-handler/main.go (100%) rename {examples => _examples}/decode/main.go (100%) rename {examples => _examples}/groups/main.go (100%) rename {examples => _examples}/hello-world/main.go (87%) rename {examples => _examples}/middleware/logging-recovery/logging_recovery.go (100%) rename {examples => _examples}/native/main.go (100%) rename {examples => _examples}/websockets/main.go (99%) diff --git a/README.md b/README.md index 8c7fdaa..81c9331 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## LARS -![Project status](https://img.shields.io/badge/version-4.0.0-green.svg) +![Project status](https://img.shields.io/badge/version-4.0.0-green.svg) [![Build Status](https://semaphoreci.com/api/v1/projects/4351aa2d-2f94-40be-a6ef-85c248490378/679708/badge.svg)](https://semaphoreci.com/joeybloggs/lars) [![Coverage Status](https://coveralls.io/repos/github/go-playground/lars/badge.svg?branch=master)](https://coveralls.io/github/go-playground/lars?branch=master) [![Go Report Card](https://goreportcard.com/badge/go-playground/lars)](https://goreportcard.com/report/go-playground/lars) @@ -7,19 +7,19 @@ ![License](https://img.shields.io/dub/l/vibe-d.svg) [![Gitter](https://badges.gitter.im/go-playground/lars.svg)](https://gitter.im/go-playground/lars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -LARS is a fast radix-tree based, zero allocation, HTTP router for Go. [ view examples](https://github.com/go-playground/lars/tree/master/examples). If looking for a more pure Go solution, be sure to check out [pure](https://github.com/go-playground/pure) which is essentially a pure version of lars +LARS is a fast radix-tree based, zero allocation, HTTP router for Go. [ view examples](https://github.com/go-playground/lars/tree/master/_examples). If looking for a more pure Go solution, be sure to check out [pure](https://github.com/go-playground/pure) which is essentially a pure version of lars Why Another HTTP Router? ------------------------ -Have you ever been painted into a corner by a framework, **ya me too!** and I've noticed that allot of routers out there, IMHO, are adding so much functionality that they are turning into Web Frameworks, (which is fine, frameworks are important) however, not at the expense of flexibility and configurability. So with no further ado, introducing LARS an HTTP router that can be your launching pad in creating a framework for your needs. How? Context is an interface [see example here](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go), where you can add as little or much as you want or need and most importantly...**under your control**. +Have you ever been painted into a corner by a framework, **ya me too!** and I've noticed that allot of routers out there, IMHO, are adding so much functionality that they are turning into Web Frameworks, (which is fine, frameworks are important) however, not at the expense of flexibility and configurability. So with no further ado, introducing LARS an HTTP router that can be your launching pad in creating a framework for your needs. How? Context is an interface [see example here](https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go), where you can add as little or much as you want or need and most importantly...**under your control**. Key & Unique Features -------------- -- [x] **Context is an interface** - this allows passing of framework/globals/application specific variables. [example](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go) +- [x] **Context is an interface** - this allows passing of framework/globals/application specific variables. [example](https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go) - [x] **Smart Route Logic** - helpful logic to help prevent adding bad routes, keeping your url's consistent. i.e. /user/:id and /user/:user_id - the second one will fail to add letting you know that :user_id should be :id - [x] **Uber simple middleware + handlers** - middleware and handlers actually have the exact same definition! - [x] **Custom Handlers** - can register custom handlers for making other middleware + handler patterns usable with this router; the best part about this is can register one for your custom context and not have to do type casting everywhere [see here](https://github.com/go-playground/lars/blob/master/examples/custom-handler/main.go) -- [x] **Diverse handler support** - Full support for standard/native http Handler + HandlerFunc + some others [see here](https://github.com/go-playground/lars/blob/master/examples/native/main.go) +- [x] **Diverse handler support** - Full support for standard/native http Handler + HandlerFunc + some others [see here](https://github.com/go-playground/lars/blob/master/_examples/native/main.go) * When Parsing a form call Context's ParseForm amd ParseMulipartForm functions and the URL params will be added into the Form object, just like query parameters are, so no extra work - [x] **Fast & Efficient** - lars uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter) so incredibly fast and efficient. @@ -32,7 +32,7 @@ go get -u github.com/go-playground/lars Usage ------ -Below is a simple example, for a full example [see here](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go) +Below is a simple example, for a full example [see here](https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go) ```go package main @@ -41,7 +41,7 @@ import ( "net/http" "github.com/go-playground/lars" - mw "github.com/go-playground/lars/examples/middleware/logging-recovery" + mw "github.com/go-playground/lars/_examples/middleware/logging-recovery" ) func main() { @@ -174,7 +174,7 @@ func Home(c *MyContext) { Decoding Body ------------- -For full example see [here](https://github.com/go-playground/lars/blob/master/examples/decode/main.go). +For full example see [here](https://github.com/go-playground/lars/blob/master/_examples/decode/main.go). currently JSON, XML, FORM + Multipart Form's are support out of the box. ```go // first argument denotes yes or no I would like URL query parameter fields @@ -253,8 +253,8 @@ comply with the following rule(s): * Are completely reusable by the community without modification -Other middleware will be listed under the examples/middleware/... folder for a quick copy/paste modify. as an example a logging or -recovery middleware are very application dependent and therefore will be listed under the examples/middleware/... +Other middleware will be listed under the _examples/middleware/... folder for a quick copy/paste modify. as an example a logging or +recovery middleware are very application dependent and therefore will be listed under the _examples/middleware/... Benchmarks ----------- diff --git a/examples/README/test.gif b/_examples/README/test.gif similarity index 100% rename from examples/README/test.gif rename to _examples/README/test.gif diff --git a/examples/README/test.go b/_examples/README/test.go similarity index 100% rename from examples/README/test.go rename to _examples/README/test.go diff --git a/examples/all-in-one/main.go b/_examples/all-in-one/main.go similarity index 100% rename from examples/all-in-one/main.go rename to _examples/all-in-one/main.go diff --git a/examples/custom-handler/main.go b/_examples/custom-handler/main.go similarity index 100% rename from examples/custom-handler/main.go rename to _examples/custom-handler/main.go diff --git a/examples/decode/main.go b/_examples/decode/main.go similarity index 100% rename from examples/decode/main.go rename to _examples/decode/main.go diff --git a/examples/groups/main.go b/_examples/groups/main.go similarity index 100% rename from examples/groups/main.go rename to _examples/groups/main.go diff --git a/examples/hello-world/main.go b/_examples/hello-world/main.go similarity index 87% rename from examples/hello-world/main.go rename to _examples/hello-world/main.go index 07d5ee6..e677686 100644 --- a/examples/hello-world/main.go +++ b/_examples/hello-world/main.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/go-playground/lars" - mw "github.com/go-playground/lars/examples/middleware/logging-recovery" + mw "github.com/go-playground/lars/_examples/middleware/logging-recovery" ) func main() { diff --git a/examples/middleware/logging-recovery/logging_recovery.go b/_examples/middleware/logging-recovery/logging_recovery.go similarity index 100% rename from examples/middleware/logging-recovery/logging_recovery.go rename to _examples/middleware/logging-recovery/logging_recovery.go diff --git a/examples/native/main.go b/_examples/native/main.go similarity index 100% rename from examples/native/main.go rename to _examples/native/main.go diff --git a/examples/websockets/main.go b/_examples/websockets/main.go similarity index 99% rename from examples/websockets/main.go rename to _examples/websockets/main.go index b16a168..dff0c7b 100644 --- a/examples/websockets/main.go +++ b/_examples/websockets/main.go @@ -13,7 +13,7 @@ import ( "time" "github.com/go-playground/lars" - "github.com/go-playground/lars/examples/middleware/logging-recovery" + "github.com/go-playground/lars/_examples/middleware/logging-recovery" "github.com/gorilla/websocket" ) diff --git a/doc.go b/doc.go index 6fa2886..223e949 100644 --- a/doc.go +++ b/doc.go @@ -4,7 +4,7 @@ Package lars - Library Access/Retrieval System, is a fast radix-tree based, zero Usage -Below is a simple example, for a full example see here https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go +Below is a simple example, for a full example see here https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go package main @@ -12,7 +12,7 @@ Below is a simple example, for a full example see here https://github.com/go-pla "net/http" "github.com/go-playground/lars" - mw "github.com/go-playground/lars/examples/middleware/logging-recovery" + mw "github.com/go-playground/lars/_examples/middleware/logging-recovery" ) func main() { @@ -154,7 +154,7 @@ example context + custom handlers Decoding Body -For full example see https://github.com/go-playground/lars/blob/master/examples/decode/main.go +For full example see https://github.com/go-playground/lars/blob/master/_examples/decode/main.go currently JSON, XML, FORM + Multipart Form's are support out of the box. // first argument denotes yes or no I would like URL query parameter fields