mjl blog
December 25th 2015

Serving a godoc vfs.FileSystem with http.FileServer

The short version: See https://godoc.org/bitbucket.org/mjl/httpvfs for a tiny library that makes it easy to use net/http’s FileServer() on a vfs.FileSystem from godoc.

The longer version: I’ve been writing a few HTTP services in Go again. The “asset” library has been very useful in making fat binaries, resulting in a single file that contains all static assets too. See https://godoc.org/bitbucket.org/mjl/asset. It appends a zip file to a binary, then uses godoc’s zipfs to read files from the embedded zip file. Zipfs is a vfs.FileSystem, so that is what the asset library uses too.

So, I noticed I kept writing a function to serve static file from a vfs.FileSystem (the zipfs from the binary). That seems wasteful, given the “net/http” library has a handler to serve static files, it’s called http.FileServer(). However, it only works on types implementing the http.FileSystem interface. So that’s what this new httpvfs library does.

If you are making a web server with the net/http library, put the static files in a directory “assets/” and put your files that need embedding in the binary in it. For example “assets/static/css/style.css”. Now use code like this as “main.go”:

package main

import (
    "bitbucket.org/mjl/asset"
    "bitbucket.org/mjl/httpvfs"
    "golang.org/x/tools/godoc/vfs"
    "log"
    "net/http"
)

func main() {
    fs := asset.Fs()
    if err := asset.Error(); err != nil {
        log.Printf("assets: using local file system...")
        fs = vfs.OS("assets")
    }

    http.Handle("/static/", http.FileServer(httpvfs.New(fs)))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Create a file:

mkdir -p assets/static/css && echo 'body {font-family:sans-serif;}' >assets/static/css

Run this:

go build && ./main

And check if it works:

curl -v http://localhost:8080/static/css/style.css

Now let’s make the binary fat:

(cd assets && zip -r0 ../assets.zip .) && cat assets.zip >>main

Restart the binary:

./main

Notice you won’t get an warning message about using the local file system as you got before. Next, let’s check fetching the file still works:

curl -v http://localhost:8080/static/css/style.css

That’s it. Let me know what you think.

Comments