Go の http.Client で外部 API を叩く:Get・Post・ヘッダー設定の基本
Go で外部の API を呼び出すには、標準ライブラリの net/http パッケージに含まれる http.Client を使います。GET・POST・ヘッダー設定まで、すべて標準ライブラリだけで対応可能です。
GET リクエストを送る
もっとも基本的な GET リクエストは http.Get で送れます。
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, err := http.Get("https://httpbin.org/get")
if err != nil {
fmt.Println("エラー:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("読み取りエラー:", err)
return
}
fmt.Println(string(body))
}http.Get はレスポンスとエラーを返します。レスポンスのボディは io.ReadAll でバイト列として読み取れますが、必ず defer resp.Body.Close() でクローズする必要があります。クローズしないとコネクションがリークし、長時間動くプログラムではリソースが枯渇する原因になります。
http.Get でリクエスト送信
resp.Body をクローズ予約(defer)
io.ReadAll でボディ読み取り
取得したデータを処理
POST リクエストを送る
JSON を送信する POST リクエストもシンプルに書けます。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
data := map[string]string{
"name": "Alice",
"email": "alice@example.com",
}
jsonData, err := json.Marshal(data)
if err != nil {
fmt.Println("JSON 変換エラー:", err)
return
}
resp, err := http.Post(
"https://httpbin.org/post",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
fmt.Println("リクエストエラー:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("読み取りエラー:", err)
return
}
fmt.Println(string(body))
}http.Post の第 2 引数には Content-Type を指定します。JSON を送るなら "application/json" が定番です。リクエストボディは bytes.NewBuffer で io.Reader に変換して渡します。
ポイントは json.Marshal でマップや構造体を JSON バイト列に変換する部分です。構造体を使う場合はフィールドタグでキー名を制御できます。
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}http.NewRequest でヘッダーを設定する
http.Get や http.Post は便利ですが、カスタムヘッダーを追加したい場合は http.NewRequest を使います。API キーの送信や認証トークンの付与が必要なケースでは、こちらが必須になります。
req, err := http.NewRequest("GET", "https://api.example.com/data", nil)
if err != nil {
fmt.Println("リクエスト作成エラー:", err)
return
}
req.Header.Set("Authorization", "Bearer your-token-here")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("リクエストエラー:", err)
return
}
defer resp.Body.Close()http.NewRequest でリクエストオブジェクトを作り、Header.Set でヘッダーを追加してから client.Do で送信する流れです。
手軽だがヘッダーのカスタマイズができない。シンプルなリクエスト向き。
柔軟にヘッダーやメソッドを設定可能。認証付き API や複雑なリクエストに対応。
タイムアウトを設定する
デフォルトの http.Client にはタイムアウトが設定されていません。外部 API が応答しない場合、プログラムが永遠に待ち続ける危険があります。
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get("https://httpbin.org/delay/5")
if err != nil {
fmt.Println("タイムアウトまたはエラー:", err)
return
}
defer resp.Body.Close()Timeout フィールドに time.Duration を設定するだけで、指定時間を超えたリクエストは自動的にキャンセルされます。本番コードでは必ず設定しておきましょう。10 秒程度が一般的な目安ですが、API の特性に応じて調整してください。
ステータスコードを確認する
API を叩いたら、レスポンスのステータスコードを確認する習慣をつけましょう。http.Get などが err == nil でも、サーバーが 404 や 500 を返している可能性があります。
resp, err := http.Get("https://httpbin.org/status/404")
if err != nil {
fmt.Println("通信エラー:", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("想定外のステータス: %d\n", resp.StatusCode)
return
}
fmt.Println("成功!")err は通信レベルのエラー(DNS 解決失敗やタイムアウトなど)だけを捕捉します。HTTP レベルのエラーは resp.StatusCode を見て自分で判定する必要がある点に注意してください。