🐛 bug: fix naming of routes inside groups (#2199)

* 🐛 bug: fix naming of routes inside groups

* fix tests

* bug: fix naming of routes inside groups

Co-authored-by: René Werner <rene@gofiber.io>
pull/2107/head
M. Efe Çetin 2022-11-09 18:03:16 +03:00 committed by GitHub
parent 13247206ab
commit 581af0052d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 30 deletions

23
app.go
View File

@ -9,6 +9,8 @@ package fiber
import ( import (
"bufio" "bufio"
"encoding/json"
"encoding/xml"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@ -20,9 +22,6 @@ import (
"sync" "sync"
"time" "time"
"encoding/json"
"encoding/xml"
"github.com/gofiber/fiber/v2/utils" "github.com/gofiber/fiber/v2/utils"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@ -109,7 +108,6 @@ type App struct {
hooks *Hooks hooks *Hooks
// Latest route & group // Latest route & group
latestRoute *Route latestRoute *Route
latestGroup *Group
// TLS handler // TLS handler
tlsHandler *TLSHandler tlsHandler *TLSHandler
// Mount fields // Mount fields
@ -485,7 +483,6 @@ func New(config ...Config) *App {
getBytes: utils.UnsafeBytes, getBytes: utils.UnsafeBytes,
getString: utils.UnsafeString, getString: utils.UnsafeString,
latestRoute: &Route{}, latestRoute: &Route{},
latestGroup: &Group{},
} }
// Define hooks // Define hooks
@ -583,8 +580,10 @@ func (app *App) SetTLSHandler(tlsHandler *TLSHandler) {
// Name Assign name to specific route. // Name Assign name to specific route.
func (app *App) Name(name string) Router { func (app *App) Name(name string) Router {
app.mutex.Lock() app.mutex.Lock()
if strings.HasPrefix(app.latestRoute.path, app.latestGroup.Prefix) {
app.latestRoute.Name = app.latestGroup.name + name latestGroup := app.latestRoute.group
if latestGroup != nil {
app.latestRoute.Name = latestGroup.name + name
} else { } else {
app.latestRoute.Name = name app.latestRoute.Name = name
} }
@ -656,7 +655,7 @@ func (app *App) Use(args ...interface{}) Router {
panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg))) panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
} }
} }
app.register(methodUse, prefix, handlers...) app.register(methodUse, prefix, nil, handlers...)
return app return app
} }
@ -715,7 +714,7 @@ func (app *App) Patch(path string, handlers ...Handler) Router {
// Add allows you to specify a HTTP method to register a route // Add allows you to specify a HTTP method to register a route
func (app *App) Add(method, path string, handlers ...Handler) Router { func (app *App) Add(method, path string, handlers ...Handler) Router {
return app.register(method, path, handlers...) return app.register(method, path, nil, handlers...)
} }
// Static will create a file server serving static files // Static will create a file server serving static files
@ -736,10 +735,10 @@ func (app *App) All(path string, handlers ...Handler) Router {
// api := app.Group("/api") // api := app.Group("/api")
// api.Get("/users", handler) // api.Get("/users", handler)
func (app *App) Group(prefix string, handlers ...Handler) Router { func (app *App) Group(prefix string, handlers ...Handler) Router {
if len(handlers) > 0 {
app.register(methodUse, prefix, handlers...)
}
grp := &Group{Prefix: prefix, app: app} grp := &Group{Prefix: prefix, app: app}
if len(handlers) > 0 {
app.register(methodUse, prefix, grp, handlers...)
}
if err := app.hooks.executeOnGroupHooks(*grp); err != nil { if err := app.hooks.executeOnGroupHooks(*grp); err != nil {
panic(err) panic(err)
} }

View File

@ -587,15 +587,16 @@ func Test_App_Route_Naming(t *testing.T) {
app.Name("doe") app.Name("doe")
jane := app.Group("/jane").Name("jane.") jane := app.Group("/jane").Name("jane.")
group := app.Group("/group")
subGroup := jane.Group("/sub-group").Name("sub.")
jane.Get("/test", handler).Name("test") jane.Get("/test", handler).Name("test")
jane.Trace("/trace", handler).Name("trace") jane.Trace("/trace", handler).Name("trace")
group := app.Group("/group")
group.Get("/test", handler).Name("test") group.Get("/test", handler).Name("test")
app.Post("/post", handler).Name("post") app.Post("/post", handler).Name("post")
subGroup := jane.Group("/sub-group").Name("sub.")
subGroup.Get("/done", handler).Name("done") subGroup.Get("/done", handler).Name("done")
utils.AssertEqual(t, "post", app.GetRoute("post").Name) utils.AssertEqual(t, "post", app.GetRoute("post").Name)

View File

@ -7,12 +7,12 @@ package fiber
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
) )
// Group struct // Group struct
type Group struct { type Group struct {
app *App app *App
parentGroup *Group
name string name string
Prefix string Prefix string
@ -21,15 +21,14 @@ type Group struct {
// Name Assign name to specific route. // Name Assign name to specific route.
func (grp *Group) Name(name string) Router { func (grp *Group) Name(name string) Router {
grp.app.mutex.Lock() grp.app.mutex.Lock()
if strings.HasPrefix(grp.Prefix, grp.app.latestGroup.Prefix) {
grp.name = grp.app.latestGroup.name + name if grp.parentGroup != nil {
grp.name = grp.parentGroup.name + name
} else { } else {
grp.name = name grp.name = name
} }
grp.app.latestGroup = grp if err := grp.app.hooks.executeOnGroupNameHooks(*grp); err != nil {
if err := grp.app.hooks.executeOnGroupNameHooks(*grp.app.latestGroup); err != nil {
panic(err) panic(err)
} }
grp.app.mutex.Unlock() grp.app.mutex.Unlock()
@ -64,15 +63,15 @@ func (grp *Group) Use(args ...interface{}) Router {
panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg))) panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
} }
} }
grp.app.register(methodUse, getGroupPath(grp.Prefix, prefix), handlers...) grp.app.register(methodUse, getGroupPath(grp.Prefix, prefix), grp, handlers...)
return grp return grp
} }
// Get registers a route for GET methods that requests a representation // Get registers a route for GET methods that requests a representation
// of the specified resource. Requests using GET should only retrieve data. // of the specified resource. Requests using GET should only retrieve data.
func (grp *Group) Get(path string, handlers ...Handler) Router { func (grp *Group) Get(path string, handlers ...Handler) Router {
path = getGroupPath(grp.Prefix, path) grp.Add(MethodHead, path, handlers...)
return grp.app.Add(MethodHead, path, handlers...).Add(MethodGet, path, handlers...) return grp.Add(MethodGet, path, handlers...)
} }
// Head registers a route for HEAD methods that asks for a response identical // Head registers a route for HEAD methods that asks for a response identical
@ -124,7 +123,7 @@ func (grp *Group) Patch(path string, handlers ...Handler) Router {
// Add allows you to specify a HTTP method to register a route // Add allows you to specify a HTTP method to register a route
func (grp *Group) Add(method, path string, handlers ...Handler) Router { func (grp *Group) Add(method, path string, handlers ...Handler) Router {
return grp.app.register(method, getGroupPath(grp.Prefix, path), handlers...) return grp.app.register(method, getGroupPath(grp.Prefix, path), grp, handlers...)
} }
// Static will create a file server serving static files // Static will create a file server serving static files
@ -147,9 +146,17 @@ func (grp *Group) All(path string, handlers ...Handler) Router {
func (grp *Group) Group(prefix string, handlers ...Handler) Router { func (grp *Group) Group(prefix string, handlers ...Handler) Router {
prefix = getGroupPath(grp.Prefix, prefix) prefix = getGroupPath(grp.Prefix, prefix)
if len(handlers) > 0 { if len(handlers) > 0 {
_ = grp.app.register(methodUse, prefix, handlers...) _ = grp.app.register(methodUse, prefix, grp, handlers...)
} }
return grp.app.Group(prefix)
// Create new group
newGrp := &Group{Prefix: prefix, app: grp.app, parentGroup: grp}
if err := grp.app.hooks.executeOnGroupHooks(*newGrp); err != nil {
panic(err)
}
return newGrp
} }
// Route is used to define routes with a common prefix inside the common function. // Route is used to define routes with a common prefix inside the common function.

View File

@ -52,6 +52,7 @@ type Route struct {
root bool // Path equals '/' root bool // Path equals '/'
path string // Prettified path path string // Prettified path
routeParser routeParser // Parameter parser routeParser routeParser // Parameter parser
group *Group // Group instance. used for routes in groups
// Public fields // Public fields
Method string `json:"method"` // HTTP method Method string `json:"method"` // HTTP method
@ -211,7 +212,7 @@ func (app *App) copyRoute(route *Route) *Route {
} }
} }
func (app *App) register(method, pathRaw string, handlers ...Handler) Router { func (app *App) register(method, pathRaw string, group *Group, handlers ...Handler) Router {
// Uppercase HTTP methods // Uppercase HTTP methods
method = utils.ToUpper(method) method = utils.ToUpper(method)
// Check if the HTTP method is valid unless it's USE // Check if the HTTP method is valid unless it's USE
@ -262,6 +263,9 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) Router {
routeParser: parsedPretty, routeParser: parsedPretty,
Params: parsedRaw.params, Params: parsedRaw.params,
// Group data
group: group,
// Public data // Public data
Path: pathRaw, Path: pathRaw,
Method: method, Method: method,

View File

@ -280,7 +280,7 @@ func Test_Router_Register_Missing_Handler(t *testing.T) {
utils.AssertEqual(t, "missing handler in route: /doe\n", fmt.Sprintf("%v", err)) utils.AssertEqual(t, "missing handler in route: /doe\n", fmt.Sprintf("%v", err))
} }
}() }()
app.register("USE", "/doe") app.register("USE", "/doe", nil)
} }
func Test_Ensure_Router_Interface_Implementation(t *testing.T) { func Test_Ensure_Router_Interface_Implementation(t *testing.T) {