Many of the microservices I am working right now, are written in Golang. Most of these microservices have internal dashboards and the UI tend to be served from the respective microservices. For serving a UI from a golang service (or any other service), you need to serve the UI files from the service. But specially in Golang, this used to be not very straight forward. Althogh we can serve files from a certain folder using a static file server feature in Golang, the language was missing the native support to bundle ui files with the service executable. For getting this done, there are several open source golang libraries out there such as,
We we using the packer library from above. On the high level, these libraries serialized all the static content and
stored the serialized contents inside .go
files. So once we update any of the static contents, we had to run a specific command
for the serialization and generating the new .go
files.
But then on one bright sunny day, Golang team introduced their latest feature, Embedded Files in their latest version go 1.16
. Since this native way of embedding files eliminates the need of generating files explicitly and it looks more convenient, we wanted to make the switch in our services.
I faced with few challenges while doing the switch,
- Go embed directive doesn’t support paths with
..
according to the documentation (accessing the parent file) - Go embed always considers the path from the root.
eg: if the file is
project-root/static/index.html
you will be able to access the file onhttp://localhost:8080/static/index.html
As the solution to the first problem, I ended up defining the //go:embed
directive in the main.go
But as a solution to the other problem, I came up with the following implementation,
main.go
1package main23import (4 "embed"5 "log"6 "net/http"7)89//go:embed static/*10var staticContent embed.FS1112func main() {13 http.Handle("/", http.FileServer(http.FS(StaticFS{staticContent})))14 log.Fatal(http.ListenAndServe(":8080", nil))15}16
staticfs.go
1package main23import (4 "embed"5 "io/fs"6 "path"7)89type StaticFS struct {10 content embed.FS11}1213func (c StaticFS) Open(name string) (fs.File, error) {14 return c.content.Open(path.Join("static", name))15}16
You can see a working demo in below repo