SlideShare a Scribd company logo
GoでWebアプリを
開発してみよう
2016/12/08(木)
@Go言語LT大会!
「最近、Go言語始めました」の会
The Go gopher was designed by Renee French.
The gopher stickers was made by Takuya Ueda.
Licensed under the Creative Commons 3.0
Attributions license.
自己紹介
メルカリ/ソウゾウ
上田拓也
twitter: @tenntenn
■ Go歴 / GAE歴
Go:5〜6年くらい?
GAE:最近再開、GCPUG Tokyoのスタッフ
■ 業務
GAE/Goでメルカリアッテを作ってます
Goのコミュニティを盛り上げる仕事
Gopherを描く仕事(LINEスタンプ)
アジェンダ
■ net/httpパッケージ
● 動かしてみよう
● ハンドラ
● レスポンス
● リクエスト
■ html/templateパッケージ
● テンプレートエンジンとは
● 値埋め込んでみる
■ net/http/httptestパッケージ
● ハンドラをテストしてみよう
net/httpパッケージ
Hello, net/http パッケージ
■ まずは動かしてみよう
package main
import "fmt"
import "net/http"
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, "Hello, net/http!")
}
ハンドラ
■ ハンドラ
■ ハンドラの登録
func handler(w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, "Hello, net/http!")
}
http.HandleFunc("/", handler)
レスポンスを書き込むWriter
リクエスト
レスポンスの書き込み
/というパターンのパスで来たリクエストを
ハンドリングする関数を登録
HTTPサーバの起動
■ ListenAndServe
http.ListenAndServe(":8080", nil)
ホスト名:ポート番号
ホスト名を省略するとlocalhost
HTTPハンドラ
nilだとhttp.DefaultServeMux
Listenするとここで処理が
ブロックされリクエストを待つ
http.Handlerインタフェース
■ ハンドラはインタフェースとして定義される
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
ServeHTTPメソッドを持つ型が
ハンドラとして扱われる
http.Handlerの登録
■ http.Handleでhttp.Handlerを登録
func Handle(pattern string,
handler http.Handler)
ServeHTTPメソッドを持つ型が
ハンドラとして扱われる
実際には、ServeHTTPメソッドを
持つ型の具体的な値がくる
http.HandlerFunc
■ http.HandlerFuncとは?
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(
w ResponseWriter, r *Request) {
f(w, r)
}
ServeHTTPメソッドを
関数に実装させるための型
http.HandleFuncは何をしてるのか
■ http.HandleFunc
● 関数をハンドラとして登録する
● 関数をhttp.HandlerFuncに変換する
● http.Handleで登録する
func HandleFunc(
pattern string,
handler func(ResponseWriter, *Request))
Handlerは登録されるもの
Handleは登録する関数
http.ServeMuxについて
■ http.ServeMuxとは?
● 複数のハンドラをまとめる
● パスによって使うハンドラを切り替える
● 自身もhttp.Handlerを実装している
● http.Handleとhttp.HandleFuncはデ
フォルトのhttp.ServeMuxである
http.DefaultServeMuxを使用している
http.ResponseWriterについて
■ http.ResponseWriterインタフェース
● io.Writerと同じWriteメソッドをもつ
○ ResposeWriteを満たすとio.Writerを満たす
● io.Writerとしても振る舞える
○ fmt.Fprint*の引数に取れる
○ json.NewEncoderの引数に取れる
インタフェースなので
モックも作りやすい=テスト簡単
HTMLの表示
■ ResponseWriterにHTMLを書き込む
func root(w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, guestbookForm)
}
const guestbookForm = `
<html>
...
</html>
`
HTMLを書き込めばブラウザが
HTMLをレンダリングしてくれる
http.Requestについて
■ http.Requesetとは?
● HTTPリクエストを表す
● ヘッダーやBodyがとれる
● FormValueメソッドでリクエストで送られた
値を取り出せる
ユーザ入力を受け付ける
■ リクエストからFormデータを取得する
func handler(w http.ResponseWriter,
r *http.Request) {
v := r.FormValue("myvalue")
fmt.Fprint(w, v)
}
<form action="/post" method="post">
<input type="text" name="myvalue">
<input type="submit" value="post">
</form>
Go
HTML
POSTで送られた
値を取得できる
templateパッケージ
テンプレートエンジンの利用
■ html/templateを使う
● Go標準のテンプレートエンジン
● text/templateのHTML特化版
■ テンプレートの生成
■ テンプレートに埋め込む
template.New("sign").Parse(signTemplateHTML)
テンプレート名
HTML
template.Mustはエラーを
panicに変換する関数
signTemplate.Execute(w, r.FormValue("content"))
リクエストから貰った値を埋め込む
よく使うテンプレートの記法
■ その文脈でトップレベルのデータを埋め込む
■ フィールドやメソッド
■ 条件分岐
■ 繰り返し
{{.}}
{{.Filed}}
{{.Method arg1 arg2}}
{{if .}}{{.Filed}}{{else}}NO{{end}}
{{range .}}{{.}}{{end}
rangeの中の
{{.}}は要素になる
データの埋め込み
■ HTMLにリクエストの値を埋め込む
const signTemplateHTML = `
<html>
<body>
<p>You wrote:</p>
<pre>{{.}}</pre>
</body>
</html>
`
signTemplate.Execute(w, r.FormValue("content"))
ここに埋め込まれる
net/http/httptestパッケージ
httptestパッケージについて
■ 何ができるのか?
● ハンドラのテストのための機能など
● ResponseRecorder
○ ResponseWriterを実装している
● NewRequestメソッド(1.7以上)
○ 簡単にテスト用のリクエストが作れる
テストの例
■ このコードをテストする
package main
import "fmt"
import "net/http"
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, "Hello, net/http!")
}
テストの例
func TestSample(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/", nil)
handler(w, r)
rw := w.Result()
defer rw.Body.Close()
if rw.StatusCode != http.StatusOK {
t.Fatal("unexpected status code")
}
b, err := ioutil.ReadAll(rw.Body)
if err != nil {t.Fatal("unexpected error)}
const expected = "Hello, net/http!"
if s := string(b); s != expected {
t.Fatalf("unexpected response: %s", s)
}
}
テスト用のReponseWriterと
Requestを作る
まとめ
● net/httpパッケージで簡単にHTTPサーバ作
れる
● html/templateパッケージでHTML用のテン
プレートエンジンが提供されている
● net/http/httptestパッケージでハンドラ
のテストができる
Thank you!
twitter: @tenntenn
Qiita: tenntenn
connpass: tenntenn

More Related Content

Goでwebアプリを開発してみよう