[Go] Go で SSR をする

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 . }} のように . のみを使って参照する。