解答 03.3 — net/http でWebサーバーを作る(statusEcho)¶
このノートブックは 03.3-http-server.ipynb の練習問題の解答です。
先に自分の力で解いてから、答え合わせに使ってください。
前提コード(問題ノートブックと同じ定義)¶
In [1]:
import (
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strconv"
"strings"
)
var ErrUnanswered = errors.New("未回答: この関数はまだ実装されていません")
const UnansweredStr = "UNANSWERED"
解答: statusEcho¶
strconv.Atoi で文字列を整数に変換します。成功すればその整数とステータス文字列を、
失敗すれば 400 と "invalid code\n" を返します。
In [2]:
// statusEcho は、パス変数 codeStr を受け取り、
// (実際に使うステータスコード, レスポンスボディ) を返す。
func statusEcho(codeStr string) (int, string) {
code, err := strconv.Atoi(codeStr)
if err != nil {
return http.StatusBadRequest, "invalid code\n"
}
return code, fmt.Sprintf("status=%s\n", codeStr)
}
チェック(問題ノートブックと同じ期待値)¶
In [3]:
import "reflect"
import "fmt"
func mustEqual(got, want any, name string) {
if reflect.DeepEqual(got, want) {
fmt.Printf("✅ Passed: %s\n", name)
return
}
panic(fmt.Sprintf("❌ %s\n got = %v (%T)\n want = %v (%T)", name, got, got, want, want))
}
In [4]:
%%
status1, body1 := statusEcho("201")
mustEqual(status1, 201, `statusEcho("201") のステータス`)
mustEqual(body1, "status=201\n", `statusEcho("201") のボディ`)
status2, body2 := statusEcho("abc")
mustEqual(status2, 400, `statusEcho("abc") は 400`)
mustEqual(body2, "invalid code\n", `statusEcho("abc") のボディ`)
// 実際に ServeMux + httptest.NewServer に組み込み、本物の HTTP レスポンスとしても確認する。
checkMux := http.NewServeMux()
checkMux.HandleFunc("GET /status/{code}", func(w http.ResponseWriter, r *http.Request) {
status, body := statusEcho(r.PathValue("code"))
w.WriteHeader(status)
fmt.Fprint(w, body)
})
checkSrv := httptest.NewServer(checkMux)
defer checkSrv.Close()
resp, err := http.Get(checkSrv.URL + "/status/201")
if err != nil {
panic(err)
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
mustEqual(resp.StatusCode, 201, "実際の HTTP レスポンスのステータスも 201")
mustEqual(strings.TrimSpace(string(b)), "status=201", "実際の HTTP レスポンスのボディも一致")
fmt.Println("🎉 すべてのチェックが通りました")
✅ Passed: statusEcho("201") のステータス
✅ Passed: statusEcho("201") のボディ
✅ Passed: statusEcho("abc") は 400
✅ Passed: statusEcho("abc") のボディ
✅ Passed: 実際の HTTP レスポンスのステータスも 201 ✅ Passed: 実際の HTTP レスポンスのボディも一致 🎉 すべてのチェックが通りました
解説¶
strconv.Atoi(codeStr)— 文字列を整数に変換する標準ライブラリの関数です。第2戻り値のerrorがnilでなければ変換失敗(数字以外の文字が含まれる等)を意味します- 失敗時は
http.StatusBadRequest(= 400) — 「クライアントが送ってきた値が不正」を表す ステータスコードとして 400 を使うのが定番です fmt.Sprintf("status=%s\n", codeStr)—codeStrはすでに文字列なので、変換した整数を もう一度文字列に戻す必要はありません(%dでcodeを使っても同じ結果になります)- チェックセルの後半 —
statusEchoを実際にGET /status/{code}ハンドラへ組み込み、httptest.NewServerで本物の HTTP リクエストを送って確かめています。これにより 「関数単体の戻り値」だけでなく「実際に HTTP レスポンスとして正しく反映されるか」まで検証できます
statusEcho 自体は http.ResponseWriter に依存しない純粋な関数なので、
サーバーを起動しなくてもテストできます。これは 04章で見る「ロジックを HTTP から切り離す」設計の先取りです。