1

As the title says, consider a Gin router where I want to serve static files from all routes except one. Let's say this one route is /api. A first attempt might look like this:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.StaticFS("/", gin.Dir("static", false))
    r.GET("/api/v1/foo", func(c *gin.Context) { c.JSON(200, gin.H{"foo": true}) })

    r.Run(":9955")
}

The RouterGroup.StaticFS (and Static too) under the hood joins the relative path with a wildcard path param: path.Join(relativePath, "/*filepath"). When relativePath is the root path /, it will panic with:

panic: '/api/v1/foo' in new path '/api/v1/foo' conflicts with existing wildcard '/*filepath' in existing prefix '/*filepath'

This is due to Gin's http router implementation: routing matches on the path prefix, so a wildcard on root will conflict with every other route. More details about this behavior can be found here — which is where this question was raised.

Another possible solution is to prefix the static file route, so that it doesn't conflict with /api:

r.StaticFS("/static", gin.Dir("static", false))

but this doesn't allow me to serve assets from root too. How can I have a wildcard, or equivalent, on root and still match on one specific path?

blackgreen
  • 34,072
  • 23
  • 111
  • 129

1 Answers1

5

There is a package called static for this.

https://github.com/gin-contrib/static#canonical-example

just modify the example as follows

package main

import (
  "github.com/gin-contrib/static"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()

  // server a directory called static
  r.Use(static.Serve("/", static.LocalFile("static", false)))
  
  // And any route as usual   
  r.GET("/api/ping", func(c *gin.Context) {
    c.String(200, "ping")
  })

  r.Run(":9955")
}
obarisk
  • 86
  • 1
  • 5
  • 1
    thank you, this is a good solution for most cases! just keep in mind that `gin-contrib/static` makes a file system call at each request before routing to the other handlers. It also could fail in a few (admittedly rare) cases. Please find a general discussion in the thread linked at the top of this question – blackgreen May 20 '22 at 13:08
  • You can also try this: router.NoRoute(gin.WrapH(http.FileServer(http.Dir("static")))) router.GET("/api/test", ...) – lechat May 27 '23 at 10:42