1. 存在する商品
  2. 2件目
  3. 存在しないID
  4. 数値でないID
コース一覧
Go入門
詳細APIと404

Go入門

変数とゼロ値、Go唯一のループであるfor、複数戻り値とエラー処理、スライスとマップ、構造体とメソッド、ゴルーチンによる並行処理、net/httpによるAPI開発まで、Goの基礎を、毎レッスン実際にコードを書き、フリマアプリのAPIをGoで作りながら学びます。

1
Hello, Go
01. Goとは15分
02. 実行してみる15分
03. packageとmain15分
04. fmtで出力する15分
05. go buildと1バイナリ15分
06. つくる: 起動バナー20分
07. 第1章クイズ10分
2
変数と型
01. varで宣言する15分
02. := の短縮宣言15分
03. ゼロ値(Goならでは)15分
04. 基本の型15分
05. 暗黙変換なし15分
06. 定数とiota15分
07. つくる: 商品データ表示20分
08. 第2章クイズ10分
3
制御構文(forしかない世界)
01. Goのif15分
02. forしかない世界15分
03. forの七変化15分
04. Goのswitch15分
05. 定番: FizzBuzz15分
06. ループで集計15分
07. つくる: 商品集計20分
08. 第3章クイズ10分
4
関数とエラー処理
01. funcで関数を作る15分
02. 複数戻り値(Goならでは)15分
03. if err != nil(Goの心臓)15分
04. エラーを作る15分
05. deferで後始末15分
06. つくる: 検証つき関数群20分
07. 第4章クイズ10分
5
スライスとマップ
01. 配列15分
02. スライス15分
03. appendで育てる15分
04. rangeで走査する15分
05. マップ15分
06. カンマokイディオム15分
07. つくる: 検索と集計20分
08. 第5章クイズ10分
6
構造体とメソッド
01. 構造体15分
02. 初期化とフィールド15分
03. メソッド15分
04. ポインタレシーバ20分
05. New関数の慣習15分
06. 構造体のスライス15分
07. つくる: Itemで再設計20分
08. 第6章クイズ10分
7
ゴルーチンと並行処理のさわり
01. ゴルーチン15分
02. チャネル20分
03. 待ち合わせ20分
04. 並行の落とし穴20分
05. つくる: 並行集計20分
06. 第7章クイズ10分
8
Web API(net/http)
01. サーバーを立てる20分
02. ハンドラ関数20分
03. JSONを返す20分
04. ルーティング20分
05. 一覧API20分
06. 詳細APIと40420分
07. 出品API20分
08. つくる: API主要部完成25分
09. 第8章クイズ10分
9
総合制作
01. 仕様互換を仕上げる25分
02. Node版と差し替える25分
03. 1バイナリでデプロイ25分
04. 自由拡張25分
05. 完成と次のステップ20分

詳細APIと404

パスから ID を取り出す

プレーンテキスト

GET /items/1

Go 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 で返すように揃えてください。次のつくる回で、その形に統一します。

要件

  1. r.PathValue("id") を strconv.Atoi で数値に変換する
  2. 変換に失敗したら 400 と {"error":"invalid id"} を返す
  3. 見つからなければ 404 と {"error":"not found"} を返す
  4. 見つかれば 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"}"

ヒント

最初に `strconv.Atoi(r.PathValue("id"))` で変換し、`err != nil` なら 400 を返します

次に `findItem(id)` を呼び、`!found` なら 404 を返します。判定の順番を守ってください

エラーの本文はバッククォートで囲むと書きやすくなります。ダブルクォートのエスケープが要りません

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/10

関連レッスン

  • 出品API

    POSTのボディを読んで検証し、不正なら400を返して登録できるようになります。

  • つくる: API主要部完成

    第8章の知識でエンドポイント一式を実装し、fleama API仕様との突合を通せるようになります。

  • 第8章クイズ

    net/http、ハンドラ、JSON、ルーティング、ステータスコードについての理解を確認します。

  • 仕様互換を仕上げる

    ステータスコードとエラー形式を仕様に揃え、互換のあるAPIとして仕上げられるようになります。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • リクエストWeb 通信の基本単位、ブラウザの問い合わせとサーバーの返答
  • HTTPWeb の通信プロトコル、HTTPS は TLS で暗号化したもの
  • ステータスコード200/201/404 など結果を示す3桁の数値
  • 関数処理に名前を付けて再利用できる単位
  • applicationJSON 本文を送るときの Content-Type
  • エスケープHTML 特殊文字を無害化する処理
  • エンドポイント「この URL を叩くとこの機能が動く」入口の住所
  • APIアプリ間でデータをやり取りする窓口
main.go
学習モード
エディタを読み込んでいます

メモ

詳細APIと404

⌘S で保存