実践Go言語(Effective Go)の翻訳、14回目です。
完全な訳は実践Go言語[日本語訳]にまとめてあります。


ウェブサーバ

Go言語のウェブサーバプログラムを作成して締めくくります。これは実際にはウェブ転送サーバの類です。Googleではhttp://chart.apis.google.comで、データをチャートやグラフに自動変換するサービスを提供していますが、このサービスはデータをクエリパラメータとしてURLに含めなくてはならないため対話的な使い方ができません。ここで紹介するプログラムは、文字を入力するとQRコード(テキストをエンコードした矩形マトリクス)を生成させるために先程のチャートサーバを呼び出す、ちょっとした画面を提供します。生成された画像を携帯電話のカメラで撮影するとURLなどに変換されるので、携帯電話の小さいキーを駆使してURLを入力する手間が省けます。

下はこのプログラム一式です。説明はそのあとに続きます。

package main

import (
    "flag"
    "http"
    "io"
    "log"
    "strings"
    "template"
)

var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
var fmap = template.FormatterMap{
    "html": template.HTMLFormatter,
    "url+html": UrlHtmlFormatter,
}
var templ = template.MustParse(templateStr, fmap)

func main() {
    flag.Parse()
    http.Handle("/", http.HandlerFunc(QR))
    err := http.ListenAndServe(*addr, nil)
    if err != nil {
        log.Exit("ListenAndServe:", err)
    }
}

func QR(c *http.Conn, req *http.Request) {
    templ.Execute(req.FormValue("s"), c)
}

func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) {
    template.HTMLEscape(w, strings.Bytes(http.URLEscape(v.(string))))
}

const templateStr = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{.section @}
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={@|url+html}"
/>
<br>
{@|html}
<br>
<br>
{.end}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>
</body>
</html>
`

main関数までは簡単に説明します。まずサーバのHTTPポート番号のデフォルト値をflagに設定しています。変数templは目新しい部分で、ページを表示するためにサーバ上で実行されるHTMLテンプレートを構築しています。これについては後でもう少し説明します。

main関数で起動パラメータの解析(flag.Parse)後、以前説明した方法でサーバのルートパスとQR関数とを紐付けています。続いてサーバを起動するためにhttp.ListenAndServeが呼び出されます。サーバが動いている間は、ここでブロックされ続けます。

QR関数では、入力フォームデータが含まれているリクエストを受け取り、そのフォーム内のsと名付けられたデータを使ってテンプレート処理を実行します。

このテンプレートパッケージは、json-templateを参考に作られており、とても高機能です。このサーバプログラムでは、ほんの触り程度しか紹介しませんが、テンプレートパッケージの主用途はテンプレートテキストの一部分をtempl.Executeに渡されたデータから得られた要素(この場合はフォームの値)で書き換えることです。テンプレートテキスト(templateStr)内の波括弧{}で囲まれている部分でテンプレートの動作を指定します。{.section @}から{.end}までの部分はデータ項目@の値を伴って実行されます。この@は「カレントのアイテム」を表しており、今回の値はフォーム値です。(文字列が空のときは、テンプレートの該当部分は出力されません。)

{@|url+html}の箇所では、フォーマッタマップ(fmap)に"url+html"という名前で登録されているフォーマット用関数を使ってデータを処理するよう指定しています。実際に登録されているUrlHtmlFormatter関数では、ウェブページ上で文字列を安全に表示させるためのサニタイズ処理を行います。

テンプレート内のその他の文字列はただのHTMLで、ページが読み込まれたときに表示されます。ここでは駆け足で説明したので、詳しくはテンプレートパッケージのドキュメントを参照ください。

数行のコードと、データと掛け合わせて出力するHTMLテキストだけで便利なウェブサーバが手に入りました。このようにGo言語はたった数行でも色々なことが行える高機能な言語です。