GoでWebサービスを作る時は、バックエンドだけをGoで書いてフロントは別のFWで用意するケースが多いと思うが、Goで直接HTMLを返したいような用途もあるかもしれない。
自分は特定のページだけOGPに対応させたかったので、Goで直接動的に生成したHTMLを返したいということがあった。
その方法もちゃんと標準ライブラリで用意されているので安心。html/template
を使う。
main.go
package main
import (
"net/http"
"html/template"
"os"
"github.com/go-chi/chi"
)
func main() {
r := chi.NewRouter()
r.Get("/", testHandler)
http.ListenAndServe(":9999", r)
}
func testHandler(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseFiles("template/sample.html")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "template error: %v", err)
return
}
values := []string{"a", "b", "c"}
if err := t.Execute(w, struct {
Title string
Values []string
}{
Title: "hogehoge",
Values: values
}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "failed to execute template: %v", err)
return
}
}
template/sample.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ .Title }}</title>
</head>
<body>
<div>
{{ range .Values }}
<div>{{.}}</div>
{{ end }}
</div>
</body>
</html>
このように {{ }} でくくることで与えた引数の値を呼び出すことができるので、動的にHTMLを出力することができる。
range を使うことで、スライスをループ処理することもできる。
この場合は構造体を渡して、構造体の中の配列を参照しているが、配列を直接渡した場合は {{ range . }} のように . のみを使って参照する。