gogo-fiber

Using GetRoutes() in goFiber/v2 returns all routes twice


While fiddling around with gofiber (v2) to learn about it - going through the official docs and trying stuff out; printing all the routes with GetRoutes() returns all the routes but twice.

There is no mention of this anywhere in the docs, and logically this should not be the case. As a beginner to gofiber I cannot understand why this is.

Source Code

// file = main.go
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "time"

    "github.com/gofiber/fiber/v2"
)

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

    // serving static files
    app.Static("/static", "./public", fiber.Static{
        Compress:      true,
        ByteRange:     true,
        Browse:        true,
        Index:         "index.html",
        CacheDuration: 10 * time.Second,
        MaxAge:        3600,
    }).Name("static")

    // Grouping APIs into their versions
    v1 := app.Group("/api/v1")
    v1.Name("api-v1-")
    v1.Get("/list", func(c *fiber.Ctx) error {
        return c.SendString("v1: /list")
    }).Name("list")
    v1.Get("/user", func(c *fiber.Ctx) error {
        return c.SendString("v1: /user")
    }).Name("user")

    v2 := app.Group("/api/v2")
    v2.Name("api-v2-")
    v2.Get("/list", func(c *fiber.Ctx) error {
        return c.SendString("v2: /list")
    }).Name("list")
    v2.Get("/user", func(c *fiber.Ctx) error {
        return c.SendString("v2: /user")
    }).Name("user")

    // Routes
    app.Route("/route", func(router fiber.Router) {
        router.Get("/foo", func(c *fiber.Ctx) error {
            return c.SendString("/route/foo")
        }).Name("route-foo")
        router.Get("/bar", func(c *fiber.Ctx) error {
            return c.SendString("/route/bar")
        }).Name("route-bar")
    })

    // GetRoutes -> Get all Routes
    data, _ := json.MarshalIndent(app.GetRoutes(true), "", " ")
    fmt.Println(string(data))

    log.Fatal(app.Listen(":3000"))
}

Output

[
 {
  "method": "GET",
  "name": "api-v1-list",
  "path": "/api/v1/list",
  "params": null
 },
 {
  "method": "GET",
  "name": "api-v1-user",
  "path": "/api/v1/user",
  "params": null
 },
 {
  "method": "GET",
  "name": "api-v2-list",
  "path": "/api/v2/list",
  "params": null
 },
 {
  "method": "GET",
  "name": "api-v2-user",
  "path": "/api/v2/user",
  "params": null
 },
 {
  "method": "GET",
  "name": "route-foo",
  "path": "/route/foo",
  "params": null
 },
 {
  "method": "GET",
  "name": "route-bar",
  "path": "/route/bar",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "api-v1-list",
  "path": "/api/v1/list",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "api-v1-user",
  "path": "/api/v1/user",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "api-v2-list",
  "path": "/api/v2/list",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "api-v2-user",
  "path": "/api/v2/user",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "route-foo",
  "path": "/route/foo",
  "params": null
 },
 {
  "method": "HEAD",
  "name": "route-bar",
  "path": "/route/bar",
  "params": null
 }
]

 ┌───────────────────────────────────────────────────┐
 │                   Fiber v2.52.8                   │
 │               http://127.0.0.1:3000               │
 │       (bound on host 0.0.0.0 and port 3000)       │
 │                                                   │
 │ Handlers ............ 13  Processes ........... 1 │
 │ Prefork ....... Disabled  PID ............... 256 │
 └───────────────────────────────────────────────────┘

As seen, each of the route is listed twice. Why is this the case?

Some more system details


Solution

  • It doesn't - it shows you the HEAD route and the GET route.

    The HEAD HTTP method requests the metadata of a resource in the form of headers that the server would have sent if the GET method was used instead. This method can be used in cases where a URL might produce a large download, for example, a HEAD request can read the Content-Length header to check the file size before downloading the file with a GET.

    In gofiber, when you register a GET route, it automatically adds the HEAD route as well:

    https://github.com/gofiber/fiber/blob/f4a9cb5023b871430b669d5ca36db1478033dad4/app.go#L707-L711

    // Get registers a route for GET methods that requests a representation
    // of the specified resource. Requests using GET should only retrieve data.
    func (app *App) Get(path string, handlers ...Handler) Router {
        return app.Head(path, handlers...).Add(MethodGet, path, handlers...)
    }