Serving an SPA with Go's "Echo"
The easiest way to server an SPA (static page application) like a React app and redirecting all paths that should be handled by the client side (React) router with the Go framework Echo is using the rewrite middleware.
Replacing the (update: not any more unmaintained) Gorilla/mux framework with Echo in đź‘Ť Get Feedback! was easy and straight forward, I did not hat to change very much. But one problem is handled differently: redirecting all paths (that are not requesting static resources and are not API endpoints) interally to index.html
, so that the single page application works in the browser – in my case a client side React (or Preact) app.
My Go application serves the front end resources (index.html
, images, styles and JavaScript) with a static file server from a directory in the same container. The resources are not embedded in the binary.
What I did with Gorilla/mux (more or less, this is inlined and shortened):
muxRouter.MatcherFunc(func(r *http.Request, match *mux.RouteMatch) bool {
return ShouldReturnIndex(r.URL.Path) || fileIsServable(r.URL.Path)
}).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if ShouldReturnIndex(request.URL.Path) {
request.URL.Path = "/"
}
fileServer.ServeHTTP(writer, request)
}).Methods("GET", "HEAD")
What this does, is: If the path matches a static resource (fileIsServable
) or matches a pattern that should be redirected to index.html
, a handler function is called which is rewriting the request URL to /
, if it matches a pattern to redirect and serves the file (if /
, this would be index.html
) with the static file server, which is an http handler: http.FileServer(http.Dir(httpRoot))
.
With Echo, it is not possible to change the url path in the same way. There are several approaches solving this with additional libraries:
While I like the idea of embedding the front end resources into the binary, for now I just wanted to replace the http routing library, without adding any more libraries and without restructuring my application.
The easiest way for me was just redirecting internally with the Echo rewrite middleware for certain paths and using Echo's static server to serve the front end resources:
e := echo.New()
e.Pre(middleware.Rewrite(map[string]string{
"^/pathprefix/*": "/",
}))
e.Static("/", fileServer.httpRoot)