TT Lab
はじめる
学ぶ 学習パス コース

Goでサーバを作る

標準ライブラリだけでサーバを作る

TT Labで続きを見る

目標

標準ライブラリだけでHTTPサーバーを作りながら、Goが何を強制するのかを見ます。 フレームワークを選ぶ前に、net/httpがすでに何を提供しているのかを確認します。

なぜ重要なのか

Goを初めて使う人は、if err != nilにうんざりすると言います。しかしその長さは コストではなく、明示性の対価です。どの行が失敗しうるのかが型に 書かれていて、無視するなら無視すると書く必要があります。

このラボでは、その代償と利点の両方を実際に体験します。そして、Goで実際に 事故が起きる場所(ゴルーチンのリーク、キャンセルの未伝播)を自分で作ってみます。

環境

ネットワークがないためgo getは動作しません。このラボは標準ライブラリだけを 使うので問題ありません。むしろそれがこのコースの論点です。

go mod init <이름>     모듈 시작
go build -o srv .      빌드
go vet ./...           흔한 실수 찾기
gofmt -l .             포맷이 어긋난 파일 나열

ステップ

  1. モジュールの初期化 → /root/work/gosrv/go.mod
  2. /healthサーバー
  3. エラーを値として扱う(%wでラップ)
  4. errors.Is/As → /root/work/gosrv/04-errors.txt
  5. JSONレスポンス → /root/work/gosrv/05-json.txt
  6. contextでキャンセルを伝播 → /root/work/gosrv/06-ctx.txt
  7. ゴルーチンのリーク → /root/work/gosrv/07-leak.txt
  8. go vet / gofmt → /root/work/gosrv/08-vet.txt

参考

モジュールを作成する

モジュールの初期化 → /root/work/gosrv/go.mod

mkdir -p /root/work/gosrv && cd /root/work/gosrv && go mod init labhub.local/gosrvを実行してください。ネットワークがないので外部パッケージは取得できません。このラボは標準ライブラリだけを使います。go.modができれば完了です。

HTTPサーバーを1つ作る

/healthサーバー

main.goでnet/httpを使って/healthを作り、8080で待ち受けさせます。go build -o srv .でビルドしたあと、./srv &で起動し、curl -s localhost:8080/healthで確認してください。フレームワークなしで、ここまでが標準ライブラリに入っています。

エラーを値として返す

エラーを値として扱う(%wでラップ)

parseAge(s string) (int, error)を作り、数字でなければエラーを返すようにします。ラップするときは、fmt.Errorf("나이 파싱(%s): %w", s, err)(韓国語の文字列は「年齢のパース」という意味です)のように%wを使ってください。%vでラップすると元のエラーが失われ、errors.Isで問い合わせられなくなります。

原因を問い合わせる

errors.Is/As → /root/work/gosrv/04-errors.txt

errors.Isまたはerrors.Asで、ラップしたエラーの原因を判別するコードを入れ、その出力を/root/work/gosrv/04-errors.txtに保存してください。ラップしたエラーから元のエラーを取り出せることを、目で確認するのが目的です。

JSONを返す

JSONレスポンス → /root/work/gosrv/05-json.txt

encoding/jsonで構造体をレスポンスします。フィールドタグ(json:"name")を付けないと、大文字のまま出力されます。Goのexportルールのためです。curl -s localhost:8080/api | jq .の結果を/root/work/gosrv/05-json.txtに保存してください。

キャンセルを伝播する

contextでキャンセルを伝播 → /root/work/gosrv/06-ctx.txt

遅いハンドラーを作り、r.Context()のDone()を監視して、クライアントが切断したら処理を止めるようにしてください。curl --max-time 1で切断し、サーバーのログにキャンセルが出力されるか確認します。出力を/root/work/gosrv/06-ctx.txtに保存してください。

ゴルーチンがリークするのを見る

ゴルーチンのリーク → /root/work/gosrv/07-leak.txt

わざとリークするゴルーチン(受け取り側のいないチャネルへ送信する)を作り、runtime.NumGoroutine()を前後で出力して/root/work/gosrv/07-leak.txtに保存してください。数が増えたまま減らないのがリークです。

先にツールに聞く

go vet / gofmt → /root/work/gosrv/08-vet.txt

go vet ./...とgofmt -l .を実行し、結果を/root/work/gosrv/08-vet.txtに保存してください。どちらも静かなら合格です。Goはフォーマットを議論しません。gofmtが正解であり、だからレビューでその話が消えます。