Monday, October 20, 2014

Serving up static files from Go / Gorilla mux

I've been playing with Go lately, just serving up a non-trivial API to kick the tires a bit.

One of the things I wanted to do was use the Swagger (https://helloreverb.com/developers/swagger) framework to document that API (I've done this before in Ruby with grape and it was a breeze).  (BTW - it was considerably more tedious to write the specification (even using the awesome https://github.com/wordnik/swagger-editor) but that's a different post...)

I needed to host the swagger-ui files (which they helpfully bundle into a 'dist' folder) and serve them up from my Go application.  The directory structure looked like this:

├── server.go
├── swagger-ui/
│   ├── css/
│   ├── images/
│   ├── index.html
│   ├── lib/

It ended up being fairly trivial to serve static files but took a little experimentation to get the Gorilla mux piece working correctly.  Here's what I ended up doing, inside 'server.go'

func main() {
router = mux.NewRouter()
router.HandleFunc("/", indexHandler)
router.HandleFunc("/api-docs", apiDocHandler)
router.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("./swagger-ui/"))))
http.Handle("/", router)
err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", router)
if err != nil {
log.Fatalln(err)
}
}

Important parts to realize:
1) you should use the PathPrefix so that the mux picks up everything inside that folder
2) you need to strip out the path prefix so that your files are served up from the correct directory, otherwise you'll end up making requests for /swagger-ui/swagger-ui/ which won't work.

5 comments:

Taylor Etheredge said...

Thank you for sharing this, was have trouble getting this to work right. Your solution worked.

Brandon [Jab] Gibson said...

This worked. Thanks for the guide, I was having issues getting this to work, and for some reason, I wasn't finding an answer at my usual sources.

Unknown said...

Thanks for the post. Does your app include a NotFound handler?

slowteetoe said...

Hi Colm, this particular project did not include a NotFound handler. If you're having issues with getting a NotFound handler to work, just make sure you don't have path prefix handlers mapped to the root.

For example, router.PathPrefix("/").Handler(somehandler) will match all routes, and your NotFound handler will never be called.

Unknown said...


Hi slowteetoe,
I have the following route set up to serve static content:
router.Handle("/", http.FileServer(http.Dir("static")))

But in order to ensure that requests for resources within the static content (e.g. http://localhost/demo) are not intercepted by the "NotFound" handler, I needed to set up this route:
router.PathPrefix("/demo/").Handler(http.StripPrefix("/demo/", http.FileServer(http.Dir("static/demo/")))

Ideally, I'd prefer not to have to hardwire (or pass in) the resource path ("/demo/" in this case) but at least it works.