From a python programmer's perspective, these are lessons I've learned from developing a web app using the Go programming language.
After understanding how to structure a go web app and route requests to a view handler, the next logical step was to use a template to render an HTML response. One of the functions I was accustomed to when I was using Django was the reverse function in Django templates. This function allowed the programmer to follow the DRY principle by referencing a URL pattern by name instead of hard-coding it in the template. I wasn't able to find something similar in Go's templating library but I was able to implement it relatively easily using the mux routing library.
First you would define your route in main or init function.
var router *mux.Router
func init() {
router = mux.NewRouter()
router.HandleFunc("/view/{pageName:.*}", viewPage).Name("view")
}
A viewPage function is called whenever a request is received at the URL "/view/myPage". The function is named "view" in the router and can be referenced by this name later in the template.
Below is a simple view handler that grabs a couple of template files and renders them to the response.
func viewPage(w http.ResponseWriter, r *http.Request) {
var page = parseTemplates(
"templates/base.html",
"templates/view.html",
)
if err := page.Execute(w, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
As you can see, the view handler passes the template files to a parseTemplates function. I created a parseTemplates function that is used by many handlers to help render the response. Below is what the function looks like.
var funcs = template.FuncMap{
"reverse": reverse,
}
func parseTemplates(files ...string) *template.Template {
// Uses the first template file as the base name
name := filepath.Base(files[0])
// Specifies a function map for this template
t := template.New(name).Funcs(funcs)
// Adds the rest of the template files to the template object
t = template.Must(t.ParseFiles(files...))
return t
}
The key thing here is the function map. The function map specifies functions that can invoked from the template. We specify a single function called "reverse" in our map. Below is the implementation.
func reverse(name string, things ...interface{}) string {
//convert the things to strings
strs := make([]string, len(things))
for i, th := range things {
strs[i] = fmt.Sprint(th)
}
//grab the route
u, err := router.Get(name).URL(strs...)
if err != nil {
panic(err)
}
return u.Path
}
The reverse function accepts a "name" argument. The function then looks up the name in the mux router and returns the path to the function. A template can use the code in the following manner.
<a href="{{ reverse "view" "pageName" "myPage" }}">Link</a>
This will generate HTML that will look like the following.
<a href="/view/myPage">Link</a>
Comments
comments powered by Disqus