詳細APIと404
パスから ID を取り出す
GET /items/1Go 1.22 からは、登録時に置き場所を書けます。
Go
mux.HandleFunc("GET /items/{id}", detailHandler)
func detailHandler(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") // "1"。文字列であることに注意
}取り出せるのは文字列です。数値として使うなら、第4章でやった strconv.Atoi で変換します。次は別の題材で、ページ番号のクエリを変換する例です。
Go
page, err := strconv.Atoi(r.URL.Query().Get("page"))
if err != nil {
w.WriteHeader(400)
return
}/items/abc のように数値でないものが来たときは、変換に失敗します。400 を返すのが正しい応答です。「そんなものは無い」ではなく「そのリクエストの書き方がおかしい」だからです。
404 を返す
見つからなかったときは 404 です。
Go
book, available := findBook(number)
if !available {
w.WriteHeader(404)
w.Write([]byte(`{"error":"not found"}`))
return
}図書を検索する findBook の例でも、第4章でやった (値, bool) の形が、そのまま HTTP のステータスコードに対応します。
演習の readID(r) はパスの取得と整数への変換をまとめた補助関数です。戻り値は (int, error) です。変換失敗を先に判定して400で抜け、成功した値だけを findItem へ渡します。検索失敗なら404、見つかれば200という順番です。
見つかった 200 とデータ
見つからない 404
リクエストが変 400エラーを表示に直すのは、いちばん外側でやる。 第4章のつくる回で書いた考え方が、ここで HTTP という形になります。内部の関数は error や bool を返し、ハンドラがステータスコードに翻訳します。
バッククォートで囲む
Go
w.Write([]byte(`{"error":"not found"}`))JSON にはダブルクォートが入るので、文字列をダブルクォートで囲むと毎回エスケープが要ります。
Go
"{\"error\":\"not found\"}" // 読みにくい
`{"error":"not found"}` // バッククォートなら素直バッククォートで囲むと、中身がそのままの文字列になります。改行もそのまま入ります。短い JSON を直接書くときに便利です。
404 の本文を揃える
前のレッスンで触れたとおり、ServeMux が自動で返す 404 は page not found という文言です。
JSON を返す API では、エラーのときだけ形が変わると使う側が困ります。
成功 {"name":"きのこ図鑑"}
404 page not found ← JSON ではない自分でハンドラを書く範囲では、エラーも JSON で返すように揃えてください。次のつくる回で、その形に統一します。
要件
readID(r)の値と error を受け取る- 変換失敗なら用意済みの400応答へ進む
findItem(id)の値と bool を受け取る- 見つからなければ用意済みの404応答へ進む。見つかれば用意済みの成功応答へ進む