つくる: API主要部完成
エンドポイント一式を1つの mux に
第8章で作ったハンドラを接続します。ハンドラは完成済みなので、今回はメソッドとパスの登録に集中します。
ServeMux パスで振り分ける
メソッド判定 GET と POST を分ける
JSON 構造体タグで返す
クエリ 検索で絞り込む
パス ID を取り出す
ステータス 200 / 201 / 400 / 404ここまで1本ずつ作ってきたものを、1つのサーバーにまとめます。
GET /items 一覧(keyword で絞り込み)
GET /items/{id} 詳細(無ければ404)
POST /items 出品(検証して201)応答の形を揃える
1つの API の中で、成功もエラーも同じ形にします。
成功 データそのもの
エラー {"error":"理由"}エラーのときだけ形が変わると、使う側が毎回確かめることになります。第8章で何度か触れた話です。
エラーを返す処理が3か所以上出てくるので、関数に切り出すと読みやすくなります。
Go
func writeError(w http.ResponseWriter, code int, message string) {
w.WriteHeader(code)
w.Write([]byte(fmt.Sprintf(`{"error":%q}`, message)))
}第4章でやった「同じ処理が2回以上出てきたら切り出す」の判断です。
ステータスコードの割り当て
GET /items 200
GET /items/1 200
GET /items/99 404 存在しない
GET /items/abc 400 IDの形が違う
POST /items 正常 201 作った
POST /items 検証NG 400 送られた内容がおかしい404 と 400 の使い分けが要点です。「そのIDのものが無い」のか「そもそもリクエストの書き方が違う」のかで分けます。
メソッドで分ける
/items は GET と POST の両方を受けます。1つのハンドラの中で分けるか、Go 1.22 の記法で別々に登録するか、どちらでも構いません。
Go
// メモAPIで読み取りと保存を分ける例
mux.HandleFunc("GET /notes", readNotes)
mux.HandleFunc("POST /notes", saveNote)別々に登録するほうが、1つ1つのハンドラが短くなります。詳細のパラメータも同じ形で登録できます。
Go
mux.HandleFunc("GET /notes/{number}", readNote)演習では、用意済みの buildMux に商品の一覧・詳細・出品を登録します。httptest が mux を通してリクエストを渡すため、サーバーを起動する必要はありません。
順番に作る
1. GET /items だけを通す
2. GET /items/{id} を足す
3. 404 と 400 を分ける
4. POST /items を足す
5. エラーの形を揃えるこの順序でハンドラを作ると不具合の場所を絞れます。今回の演習では各ハンドラは完成済みなので、ルートを1つ登録するたびに対応するテストを確かめてください。
要件
GET /itemsをlistHandlerに登録するGET /items/{id}をdetailHandlerに登録するPOST /itemsをcreateHandlerに登録する
ヒント
編集 ゆめさく編集部