詳細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
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
w.WriteHeader(400)
return
}/items/abc のように数値でないものが来たときは、変換に失敗します。400 を返すのが正しい応答です。「そんなものは無い」ではなく「そのリクエストの書き方がおかしい」だからです。
404 を返す
見つからなかったときは 404 です。
Go
item, found := findItem(id)
if !found {
w.WriteHeader(404)
w.Write([]byte(`{"error":"not found"}`))
return
}第4章でやった (値, bool) の形が、そのまま HTTP のステータスコードに対応します。
プレーンテキスト
見つかった 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 で返すように揃えてください。次のつくる回で、その形に統一します。
要件
r.PathValue("id")をstrconv.Atoiで数値に変換する- 変換に失敗したら 400 と
{"error":"invalid id"}を返す - 見つからなければ 404 と
{"error":"not found"}を返す - 見つかれば 200 と商品の JSON を返す
入出力例
callDetail("1") → "200 {"id":1,"name":"きのこ図鑑","price":1200}"
callDetail("2") → "200 {"id":2,"name":"中古スマホ","price":24800}"
callDetail("99") → "404 {"error":"not found"}"
callDetail("abc") → "400 {"error":"invalid id"}"ヒント
編集 ゆめさく編集部