Skip to content

Instantly share code, notes, and snippets.

@jonathanhudak
Created March 1, 2016 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathanhudak/5e8074660ae31c8b5174 to your computer and use it in GitHub Desktop.
Save jonathanhudak/5e8074660ae31c8b5174 to your computer and use it in GitHub Desktop.
Closures and HTTP Routing/Templates
<h1>Editing {{.Slug}}</h1>
<form action="/save/{{.Slug}}" method="POST">
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
package main
import (
"fmt"
"github.com/gorilla/mux"
"html/template"
"net/http"
"path"
)
type Page struct {
Title string
Body string
}
func PageHandler(pages map[string]Page) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
lp := path.Join("templates", "layout.html")
vars := mux.Vars(r)
fp := path.Join("templates", "404.html")
var pageContent Page
page := vars["page"]
v, ok := pages[page]
if ok {
fp := path.Join("templates", "Body.html")
pageContent = v
fmt.Println(fp, v)
}
tmpl, err := template.ParseFiles(lp, fp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, &pageContent); err != nil {
fmt.Println("err")
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
}
func main() {
pages := make(map[string]Page)
pages["index"] = Page{"Home", "Here we are"}
pages["about"] = Page{"About", "Here we are"}
r := mux.NewRouter()
r.HandleFunc("/{page}", PageHandler(pages))
// Bind to a port and pass our router in
fmt.Println("Listening on http://localhost:8000")
http.ListenAndServe(":8000", r)
}
<h1>{{.Slug}}</h1>
<p>[<a href="/edit/{{.Slug}}">edit</a>]</p>
<div>{{.Body}}</div>
package main
import (
"fmt"
"github.com/gorilla/mux"
"html/template"
"io/ioutil"
"net/http"
"path"
"regexp"
)
var edit = path.Join("templates", "edit.html")
var view = path.Join("templates", "view.html")
var templates = template.Must(template.ParseFiles(view, edit))
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
type Page struct {
Slug string
Body template.HTML
}
func (p *Page) save() error {
filename := p.Slug + ".html"
return ioutil.WriteFile(filename, []byte(p.Body), 0600)
}
func loadPage(slug string) (*Page, error) {
filename := slug + ".html"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &Page{Slug: slug, Body: template.HTML(body)}, nil
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there , %s", r.URL.Path[1:])
}
func editHandler(w http.ResponseWriter, r *http.Request) {
slug, err := getSlug(w, r)
if err != nil {
return
}
p, err := loadPage(slug)
if err != nil {
fmt.Println("err after load page", err)
p = &Page{Slug: slug}
}
editPath := path.Join("templates", "edit.html")
t, _ := template.ParseFiles(editPath)
t.Execute(w, p)
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
slug, err := getSlug(w, r)
if err != nil {
return
}
body := r.FormValue("body")
p := &Page{Slug: slug, Body: template.HTML(body)}
p.save()
http.Redirect(w, r, "/"+slug, http.StatusFound)
}
func viewHandler(w http.ResponseWriter, r *http.Request) {
slug, err := getSlug(w, r)
if err != nil {
return
}
p, err := loadPage(slug)
if err != nil {
http.Redirect(w, r, "/edit/"+slug, http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
err := templates.ExecuteTemplate(w, tmpl+".html", p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func getSlug(w http.ResponseWriter, r *http.Request) (string, error) {
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return "", errors.New("Invalid Page Title")
}
return m[2], nil // The title is the second subexpression.
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/{page}", viewHandler)
r.HandleFunc("/edit/{page}", editHandler)
r.HandleFunc("/save/{page}", saveHandler)
http.ListenAndServe(":8000", r)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment