In our first example of displaying the values from our blog from our database to the Web, we produced a hardcoded string of HTML and injected our values directly.
Following are the two lines that we used in Chapter 3, Connecting to Data:
html := `<html><head><title>` + thisPage.Title + `</title></head><body><h1>` + thisPage.Title + `</h1><div>` + thisPage.Content + `</div></body></html> fmt.Fprintln(w, html)
It shouldn't be hard to realize why this isn't a sustainable system for outputting our content to the Web. The best way to do this is to translate this into a template, so we can separate our presentation from our application.
To do this as succinctly as possible, let's modify the method that called the preceding code, ServePage
, to utilize a template instead of hardcoded HTML.
So we'll remove the HTML we placed earlier and instead reference a file that will encapsulate what we want to display. From your root directory, create a templates
subdirectory and blog.html
within it.
The following is the very basic HTML we included, feel free to add some flair:
<html> <head> <title>{{.Title}}</title> </head> <body> <h1>{{.Title}}</h1> <p> {{.Content}} </p> <div>{{.Date}}</div> </body> </html>
Back in our application, inside the ServePage
handler, we'll change our output code slightly to leave an explicit string and instead parse and execute the HTML template we just created:
func ServePage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) pageGUID := vars["guid"] thisPage := Page{} fmt.Println(pageGUID) err := database.QueryRow("SELECT page_title,page_content,page_date FROM pages WHERE page_guid=?", pageGUID).Scan(&thisPage.Title, &thisPage.Content, &thisPage.Date) if err != nil { http.Error(w, http.StatusText(404), http.StatusNotFound) log.Println("Couldn't get page!") return } // html := <html>...</html> t, _ := template.ParseFiles("templates/blog.html") t.Execute(w, thisPage) }
If, somehow, you failed to create the file or it is otherwise not accessible, the application will panic when it attempts to execute. You can also get panicked if you're referencing struct
values that don't exist—we'll need to handle errors a bit better.
The benefits of moving away from a static string should be evident, but we now have the foundation for a much more extensible presentation layer.
If we visit http://localhost:9500/page/hello-world
we'll see something similar to this: