Hi Gophers!
Messing about with a small project: it's basically a reverse proxy
that will convert json responses from the origin server to lovely html
in the client request. It decodes the json response from the origin
and passes this struct to the mustache templating engine which outputs
html.
The server has a config file allowing the user to specify url patterns
to match and destination urls to proxy to:
{
"pattern":"/hello",
"origin":"
http://example.com/some/destination",
"template":"./hello.template"
} // etc, etc
I'm having difficulty understanding our friend
httputil.NewSingleHostReverseProxy(). It may have something to do with
the way I have approached this though.
Ideally I have a http server. This assigns a handler for each entry in
the config file, matched by pattern. The handler creates a new proxy
server using httputil.NewSingleHostReverseProxy() with the origin
config parameter as the target argument. I then have a custom
http.RequestWriter that reads the json body in response, parses it,
passes it to mustache and writes the output:
...
for _, route := range config.Routes {
url, _ := url.Parse(route.origin)
MustacheHandler := NewMustacheHandler(route.TemplateCache, url)
http.Handle(route.Pattern, MustacheHandler)
}
err = http.ListenAndServe(address, nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
...
The mustache handler looks a little bit like this:
func NewMustacheHandler(template []byte, url *url.URL)
http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
mw := NewMustacheWriter(w, template)
rw := mustacheResponseWriter{Writer: mw, ResponseWriter: w}
proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ServeHTTP(rw, r)
}
}
And the mustache writer looky likey thisy:
type MustacheWriter struct {
Template []byte
w io.Writer
}
func (w MustacheWriter) Write(b []byte) (int, error) {
var f interface{}
err := json.Unmarshal(b, &f)
if err != nil {
log.Fatal(err, string(b))
}
m := f.(map[string]interface{})
d := mustache.Render(string(w.Template), m)
return w.Write([]byte(d))
}
The problem is that I keep getting "File not found" passed into the
Write(b []byte) argument, even though if I curl the URL being passed
as the origin I get valid JSON back.
So, questions!
1) Am I using NewSingleHostReverseProxy() correctly?
2) Is there a problem with my approach to this problem?
3) Is there a better way?
Cheers!
Ben