Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ v3 (feature): new mounting system #2022

Merged
merged 17 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
36 changes: 27 additions & 9 deletions group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
10 changes: 5 additions & 5 deletions hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ 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) {
t.Parallel()

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)
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -255,5 +255,5 @@ func Test_Hook_OnMount(t *testing.T) {
return nil
})

app.Mount("/sub", subApp)
app.Use("/sub", subApp)
}
8 changes: 5 additions & 3 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "/"
Expand All @@ -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 == "" {
Expand Down
38 changes: 19 additions & 19 deletions mount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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)
Expand Down Expand Up @@ -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())
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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)")
Expand All @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)")
Expand Down
2 changes: 0 additions & 2 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ type Router interface {

Route(path string) Register

Mount(prefix string, fiber *App) Router

Name(name string) Router
}

Expand Down