mirror of https://github.com/gofiber/fiber.git
✨ v3 (feature): new mounting system (#2022)
* 🔥 chore: removed mount from router * ✨ feat: new mounting system * ✨ feat: mount for group * ✅ test: updated and improve for new mount system * ♻️ refactor: better variable name * ♻️ refactor: better function naming * 🐛 fix: not mounted check * ✅ test: update onmount test if sub app is not mounted to parent * 🎨 perf: fix allocs problem * ✅ test: add benchmark for MountPath * ✨ feat: access to app's mountpath * ✅ test: remove parent app's mountpath test * remove some parts * add comment * fix Co-authored-by: Muhammed Efe Çetin <efectn@protonmail.com> Co-authored-by: RW <rene@gofiber.io>pull/2216/head
parent
709e0952e2
commit
24fd165660
35
app.go
35
app.go
|
@ -618,33 +618,50 @@ func (app *App) GetRoutes(filterUseOption ...bool) []Route {
|
|||
|
||||
// Use registers a middleware route that will match requests
|
||||
// with the provided prefix (which is optional and defaults to "/").
|
||||
// Also, you can pass another app instance as a sub-router along a routing path.
|
||||
// It's very useful to split up a large API as many independent routers and
|
||||
// compose them as a single service using Use. The fiber's error handler and
|
||||
// any of the fiber's sub apps are added to the application's error handlers
|
||||
// to be invoked on errors that happen within the prefix route.
|
||||
//
|
||||
// app.Use(func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", handler, func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use(func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", handler, func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// subApp := fiber.New()
|
||||
// app.Use("/mounted-path", subApp)
|
||||
//
|
||||
// This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
|
||||
func (app *App) Use(args ...any) Router {
|
||||
var prefix string
|
||||
var subApp *App
|
||||
var handlers []Handler
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch arg := args[i].(type) {
|
||||
case string:
|
||||
prefix = arg
|
||||
case *App:
|
||||
subApp = arg
|
||||
case Handler:
|
||||
handlers = append(handlers, arg)
|
||||
default:
|
||||
panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
|
||||
}
|
||||
}
|
||||
|
||||
if subApp != nil {
|
||||
app.mount(prefix, subApp)
|
||||
return app
|
||||
}
|
||||
|
||||
app.register([]string{methodUse}, prefix, nil, handlers...)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
|
|
36
group.go
36
group.go
|
@ -39,32 +39,50 @@ func (grp *Group) Name(name string) Router {
|
|||
|
||||
// Use registers a middleware route that will match requests
|
||||
// with the provided prefix (which is optional and defaults to "/").
|
||||
// Also, you can pass another app instance as a sub-router along a routing path.
|
||||
// It's very useful to split up a large API as many independent routers and
|
||||
// compose them as a single service using Use. The fiber's error handler and
|
||||
// any of the fiber's sub apps are added to the application's error handlers
|
||||
// to be invoked on errors that happen within the prefix route.
|
||||
//
|
||||
// app.Use(func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", handler, func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use(func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// app.Use("/api", handler, func(c fiber.Ctx) error {
|
||||
// return c.Next()
|
||||
// })
|
||||
// subApp := fiber.New()
|
||||
// app.Use("/mounted-path", subApp)
|
||||
//
|
||||
// This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
|
||||
func (grp *Group) Use(args ...any) Router {
|
||||
prefix := ""
|
||||
var subApp *App
|
||||
var handlers []Handler
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch arg := args[i].(type) {
|
||||
case string:
|
||||
prefix = arg
|
||||
case *App:
|
||||
subApp = arg
|
||||
case Handler:
|
||||
handlers = append(handlers, arg)
|
||||
default:
|
||||
panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
|
||||
}
|
||||
}
|
||||
|
||||
if subApp != nil {
|
||||
grp.mount(prefix, subApp)
|
||||
return grp
|
||||
}
|
||||
|
||||
grp.app.register([]string{methodUse}, getGroupPath(grp.Prefix, prefix), nil, handlers...)
|
||||
|
||||
return grp
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func Test_Hook_OnRoute(t *testing.T) {
|
|||
subApp := New()
|
||||
subApp.Get("/test", testSimpleHandler)
|
||||
|
||||
app.Mount("/sub", subApp)
|
||||
app.Use("/sub", subApp)
|
||||
}
|
||||
|
||||
func Test_Hook_OnRoute_Mount(t *testing.T) {
|
||||
|
@ -38,7 +38,7 @@ func Test_Hook_OnRoute_Mount(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
subApp := New()
|
||||
app.Mount("/sub", subApp)
|
||||
app.Use("/sub", subApp)
|
||||
|
||||
subApp.Hooks().OnRoute(func(r Route) error {
|
||||
require.Equal(t, "/sub/test", r.Path)
|
||||
|
@ -77,7 +77,7 @@ func Test_Hook_OnName(t *testing.T) {
|
|||
subApp.Get("/test", testSimpleHandler)
|
||||
subApp.Get("/test2", testSimpleHandler)
|
||||
|
||||
app.Mount("/sub", subApp)
|
||||
app.Use("/sub", subApp)
|
||||
|
||||
require.Equal(t, "index", buf.String())
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ func Test_Hook_OnGroup_Mount(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
micro := New()
|
||||
micro.Mount("/john", app)
|
||||
micro.Use("/john", app)
|
||||
|
||||
app.Hooks().OnGroup(func(g Group) error {
|
||||
require.Equal(t, "/john/v1", g.Prefix)
|
||||
|
@ -255,5 +255,5 @@ func Test_Hook_OnMount(t *testing.T) {
|
|||
return nil
|
||||
})
|
||||
|
||||
app.Mount("/sub", subApp)
|
||||
app.Use("/sub", subApp)
|
||||
}
|
||||
|
|
8
mount.go
8
mount.go
|
@ -36,7 +36,7 @@ func newMountFields(app *App) *mountFields {
|
|||
// compose them as a single service using Mount. The fiber's error handler and
|
||||
// any of the fiber's sub apps are added to the application's error handlers
|
||||
// to be invoked on errors that happen within the prefix route.
|
||||
func (app *App) Mount(prefix string, fiber *App) Router {
|
||||
func (app *App) mount(prefix string, fiber *App) Router {
|
||||
prefix = strings.TrimRight(prefix, "/")
|
||||
if prefix == "" {
|
||||
prefix = "/"
|
||||
|
@ -58,8 +58,10 @@ func (app *App) Mount(prefix string, fiber *App) Router {
|
|||
|
||||
// Mount attaches another app instance as a sub-router along a routing path.
|
||||
// It's very useful to split up a large API as many independent routers and
|
||||
// compose them as a single service using Mount.
|
||||
func (grp *Group) Mount(prefix string, fiber *App) Router {
|
||||
// compose them as a single service using Mount. The fiber's error handler and
|
||||
// any of the fiber's sub apps are added to the application's error handlers
|
||||
// to be invoked on errors that happen within the prefix route.
|
||||
func (grp *Group) mount(prefix string, fiber *App) Router {
|
||||
groupPath := getGroupPath(grp.Prefix, prefix)
|
||||
groupPath = strings.TrimRight(groupPath, "/")
|
||||
if groupPath == "" {
|
||||
|
|
|
@ -21,7 +21,7 @@ func Test_App_Mount(t *testing.T) {
|
|||
})
|
||||
|
||||
app := New()
|
||||
app.Mount("/john", micro)
|
||||
app.Use("/john", micro)
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/john/doe", nil))
|
||||
require.Equal(t, nil, err, "app.Test(req)")
|
||||
require.Equal(t, 200, resp.StatusCode, "Status code")
|
||||
|
@ -35,9 +35,9 @@ func Test_App_Mount_Nested(t *testing.T) {
|
|||
two := New()
|
||||
three := New()
|
||||
|
||||
two.Mount("/three", three)
|
||||
app.Mount("/one", one)
|
||||
one.Mount("/two", two)
|
||||
two.Use("/three", three)
|
||||
app.Use("/one", one)
|
||||
one.Use("/two", two)
|
||||
|
||||
one.Get("/doe", func(c Ctx) error {
|
||||
return c.SendStatus(StatusOK)
|
||||
|
@ -73,9 +73,9 @@ func Test_App_MountPath(t *testing.T) {
|
|||
two := New()
|
||||
three := New()
|
||||
|
||||
two.Mount("/three", three)
|
||||
one.Mount("/two", two)
|
||||
app.Mount("/one", one)
|
||||
two.Use("/three", three)
|
||||
one.Use("/two", two)
|
||||
app.Use("/one", one)
|
||||
|
||||
require.Equal(t, "/one", one.MountPath())
|
||||
require.Equal(t, "/one/two", two.MountPath())
|
||||
|
@ -96,7 +96,7 @@ func Test_App_ErrorHandler_GroupMount(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
v1 := app.Group("/v1")
|
||||
v1.Mount("/john", micro)
|
||||
v1.Use("/john", micro)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/v1/john/doe", nil))
|
||||
testErrorResponse(t, err, resp, "1: custom error")
|
||||
|
@ -115,7 +115,7 @@ func Test_App_ErrorHandler_GroupMountRootLevel(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
v1 := app.Group("/v1")
|
||||
v1.Mount("/", micro)
|
||||
v1.Use("/", micro)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/v1/john/doe", nil))
|
||||
testErrorResponse(t, err, resp, "1: custom error")
|
||||
|
@ -130,7 +130,7 @@ func Test_App_Group_Mount(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
v1 := app.Group("/v1")
|
||||
v1.Mount("/john", micro)
|
||||
v1.Use("/john", micro)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/v1/john/doe", nil))
|
||||
require.Equal(t, nil, err, "app.Test(req)")
|
||||
|
@ -150,7 +150,7 @@ func Test_App_UseMountedErrorHandler(t *testing.T) {
|
|||
return errors.New("something happened")
|
||||
})
|
||||
|
||||
app.Mount("/api", fiber)
|
||||
app.Use("/api", fiber)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/api", nil))
|
||||
testErrorResponse(t, err, resp, "hi, i'm a custom error")
|
||||
|
@ -168,7 +168,7 @@ func Test_App_UseMountedErrorHandlerRootLevel(t *testing.T) {
|
|||
return errors.New("something happened")
|
||||
})
|
||||
|
||||
app.Mount("/", fiber)
|
||||
app.Use("/", fiber)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/api", nil))
|
||||
testErrorResponse(t, err, resp, "hi, i'm a custom error")
|
||||
|
@ -196,7 +196,7 @@ func Test_App_UseMountedErrorHandlerForBestPrefixMatch(t *testing.T) {
|
|||
subfiber.Get("/", func(c Ctx) error {
|
||||
return errors.New("something happened")
|
||||
})
|
||||
subfiber.Mount("/third", tripleSubFiber)
|
||||
subfiber.Use("/third", tripleSubFiber)
|
||||
|
||||
f := func(c Ctx, err error) error {
|
||||
return c.Status(200).SendString("hi, i'm a custom error")
|
||||
|
@ -207,9 +207,9 @@ func Test_App_UseMountedErrorHandlerForBestPrefixMatch(t *testing.T) {
|
|||
fiber.Get("/", func(c Ctx) error {
|
||||
return errors.New("something happened")
|
||||
})
|
||||
fiber.Mount("/sub", subfiber)
|
||||
fiber.Use("/sub", subfiber)
|
||||
|
||||
app.Mount("/api", fiber)
|
||||
app.Use("/api", fiber)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/api/sub", nil))
|
||||
require.Equal(t, nil, err, "/api/sub req")
|
||||
|
@ -246,7 +246,7 @@ func Test_Ctx_Render_Mount(t *testing.T) {
|
|||
})
|
||||
|
||||
app := New()
|
||||
app.Mount("/hello", sub)
|
||||
app.Use("/hello", sub)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/hello/a", nil))
|
||||
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
|
||||
|
@ -301,8 +301,8 @@ func Test_Ctx_Render_Mount_ParentOrSubHasViews(t *testing.T) {
|
|||
return c.Render("bruh.tmpl", Map{})
|
||||
})
|
||||
|
||||
sub.Mount("/bruh", sub2)
|
||||
app.Mount("/hello", sub)
|
||||
sub.Use("/bruh", sub2)
|
||||
app.Use("/hello", sub)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/hello/world/a", nil))
|
||||
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
|
||||
|
@ -348,7 +348,7 @@ func Test_Ctx_Render_MountGroup(t *testing.T) {
|
|||
|
||||
app := New()
|
||||
v1 := app.Group("/v1")
|
||||
v1.Mount("/john", micro)
|
||||
v1.Use("/john", micro)
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/v1/john/doe", nil))
|
||||
require.Equal(t, nil, err, "app.Test(req)")
|
||||
|
|
Loading…
Reference in New Issue