fiber: Problem with Route path

Fiber version 1.12.6

Issue description Nested Route paths not invoking the correct handler.

Code snippet

func SetupRoutes(app *fiber.App) {
	todo := app.Group("/todo", middleware.Logger())

	todo.Get("/:id", handler.ReadTodo) 
	todo.Post("/", handler.CreateTodo)
	todo.Put("/:id", handler.UpdateTodo)
	todo.Delete("/:id", handler.DeleteTodo)
	todo.Get("/all/todos", handler.ReadAllTodo) 
	todo.Get("/all", handler.DummyAllHandler)  // this does not working, it always invoking todo.Get("/:id", handler.ReadTodo) 
}

Sample Code Repo

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

option := a.Group("/option")
option.Get("/:id", getById)
option.Get("/all", getAll)

But why it is not working in the above case. I am new to golang, I choose fiber coz it gives express(nodejs) like experience. The above case is still a bug, right? Is there any plan for a fix, or at least it needs to mention somewhere in the documentation

The presented case above would have the same results in Expressjs, /:id also matches /all. @kiyonlin explained this perfectly, just like in Express: order matters πŸ‘

Thanks for your reporting! But I don’t it is counted as a bug.

According to your example, there are two approaches to solve the problem:

package main

import (
	"strconv"

	"github.com/gofiber/fiber"
)

func main() {
	app := fiber.New()

	// get /option1/all => "all"
	app.Get("/option1/all", func(c *fiber.Ctx) { c.SendString("all") })
	// get /option1/1   => "1"
	app.Get("/option1/:id", func(c *fiber.Ctx) { c.Send(c.Params("id")) })

	// get /option2/1   => "1"
	app.Get("/option2/:id", func(c *fiber.Ctx) {
		// assume id is integer
		if id, err := strconv.Atoi(c.Params("id")); err != nil {
			c.Next()
		} else {
			c.Send(id)
		}
	})
	// get /option2/all => "all"
	app.Get("/option2/all", func(c *fiber.Ctx) { c.SendString("all") })

	app.Listen(3000)
}

You can place routes in the appropriate order so that Fiber can do the right thing πŸ˜„

Hi @mohanasundaramn

Seems this is not working

option := a.Group("/option")
option.Get("/:id", getById)
option.Get("/all", getAll)

When you put /:id above /all, you should do the Next thing. But your first example just do the opposite.

Btw @mohanasundaramn

But if I change the order of option/all option/:id it works. why is that?

That is because Fiber always finds the first route to match the request’s path and breaks the route chain if there is no more Next is called.

It is probably taking your path β€œall” as the id parameter. Being in the same method I assume that you must be taking it this way id = β€œall”. Try putting using StrictRouting.

app := fiber.New(&fiber.Settings{ StrictRouting: true, })

option := a.Group("/option")
option.Get("/:id", getById)
option.Get("/all", getAll)

But why it is not working in the above case. I am new to golang, I choose fiber coz it gives express(nodejs) like experience. The above case is still a bug, right? Is there any plan for a fix, or at least it needs to mention somewhere in the documentation

Nope, as I said above.

That is because Fiber always finds the first route to match the request’s path and breaks the route chain if there is no more Next is called.

@solrac97gr @kiyonlin Can you please try both codes, I still believe this is a bug

I adjusted your code:

package main

import (
	"strconv"

	"github.com/gofiber/fiber"
)

func getAll(c *fiber.Ctx) { c.SendString("option all") }

func getById(c *fiber.Ctx) { c.Send(c.Params("id")) }

func setupRoutes(a *fiber.App) {
	option := a.Group("/option")
	// πŸ‘‹πŸ‘‹πŸ‘‹ get /options/all => option all
	option.Get("/all", getAll)
	// πŸ‘‹πŸ‘‹πŸ‘‹ get /options/1 => 1
	option.Get("/:id", getById)

	option2 := a.Group("/option2")
	// πŸ‘‹πŸ‘‹πŸ‘‹ get /option2/2 => 2
	option2.Get("/:id", func(c *fiber.Ctx) {
		// assume id is integer
		if id, err := strconv.Atoi(c.Params("id")); err != nil {
			c.Next()
		} else {
			c.Send(id)
		}
	})
	// πŸ‘‹πŸ‘‹πŸ‘‹ get /option2/all => option2 all
	option2.Get("/all", func(c *fiber.Ctx) { c.SendString("option2 all") })
}

func main() {
	app := fiber.New()

	setupRoutes(app)

	app.Listen(3000)
}

@solrac97gr

It is probably taking your path β€œall” as the id parameter. Being in the same method I assume that you must be taking it this way id = β€œall”. Try putting using StrictRouting.

app := fiber.New(&fiber.Settings{ StrictRouting: true, })

app := fiber.New(&fiber.Settings{
        StrictRouting: true,
})

setting StrictRouting: true does not fix the problem still invoking todo.Get("/:id", handler.ReadTodo)