変更要約: 初版
2.5Python requestsでのAPI呼び出し
PythonのrequestsライブラリでREST APIを呼ぶスクリプトの構築——requests.get(url, headers=, params=, auth=)/requests.post(url, json=)によるリクエスト送信と、resp.status_code(コード確認・resp.raise_for_status())・resp.json()(JSONボディをdictへパース)・resp.headersの読み取り——を、「このrequestsスクリプトのどこが誤りで、なぜ期待どおり動かないか」という診断・修正として学びます。
ここまでのHTTPリクエスト・応答・認証・制約の知識を、Pythonのrequestsライブラリで実際のコードに落とし込みます。試験で問われるのは「requestsの全APIを暗記しているか」ではなく、提示されたrequestsスクリプトを読んで、期待どおり動かない原因を診断し修正できるかです。headers=とparams=を取り違える、resp.status_codeを確認せずいきなりresp.json()する、といった典型的な誤りを、コードを読んで見抜けるようにします。
2.5.1リクエストの送信
- 取得は
requests.get(url, headers=..., params=..., auth=...)。params=は辞書をクエリ文字列(?key=val)に変換して付ける({"limit":50}→?limit=50)。認証情報やAccept/Content-Typeはheaders=の辞書で渡す。このparams=(クエリ)とheaders=(ヘッダ)の役割を取り違えると、APIキーが本来ヘッダに要るのにクエリに入る等の不整合になる。 - 作成/更新は
requests.post(url, json=payload, headers=...)。json=にPython辞書を渡すと、requestsが自動でJSONへシリアライズしContent-Type: application/jsonも付ける(便利かつ付け忘れ防止)。認証はauth=(user, pass)(Basic)やheaders={"Authorization": f"Bearer {token}"}(Bearer)で渡す。
2.5.2応答の読み取り
resp.status_codeでHTTPコードを確認する(200等)。成功を確かめてから本文を扱うのが鉄則で、if resp.status_code 200:や、4xx/5xxで例外を投げるresp.raise_for_status()を使う。requestsは4xx/5xxでも例外を投げず応答オブジェクトを返すため、コードを見ずに処理を続けるとエラー応答を正常データとして扱ってしまう。- 本文の扱い:JSONなら
resp.json()でPythonのdict/listへパースする(resp.textは生文字列)。ヘッダはresp.headers(辞書ライク、resp.headers["Retry-After"]等)。注意:エラー時の本文はJSONでないことがあり、404のHTMLに対しresp.json()を呼ぶとJSONDecodeErrorで落ちる——だからこそ先にstatus_codeを確認する。
「params=はクエリ/headers=はヘッダ/json=はJSONボディ(Content-Type自動付与)」「resp.status_codeで成功確認→resp.json()でdict化」「requestsは4xx/5xxで例外を投げない(raise_for_status()で明示チェック)」「エラー本文は非JSONのことがあり、確認前のresp.json()は例外を招く」が頻出です。設問は「このrequestsスクリプトの誤りはどこか」を読んで直す形で解きましょう。
あなたは同僚のPythonスクリプトが「時々クラッシュし、時々おかしなデータを出す」という不具合を調査しています。コードの核心は次の通りです:resp = requests.get("https://api.example.com/v1/devices", params={"Authorization": "Bearer " + token}); data = resp.json(); print(data["items"])。ここには二つの独立した誤りが潜んでいます。第一に、認証情報をparams=(クエリパラメータ)に入れている点です——Authorizationはヘッダで送るべきもので、params=に置くとURLに?Authorization=Bearer...として付き、多くのAPIはこれを認証と認めず401を返します(かつトークンがURLに露出しログに残る危険もあります)。正しくはheaders={"Authorization": f"Bearer {token}"}です。第二に、resp.status_codeを確認せずいきなりresp.json()を呼んでいる点です。requestsは4xx/5xxでも例外を投げずに応答オブジェクトを返すため、認証に失敗して401が返り、その本文がJSONでない(またはエラーJSONでitemsキーが無い)場合、resp.json()がJSONDecodeErrorで落ちるか、data["items"]がKeyErrorになります——これが「時々クラッシュ」の正体です。修正版はこうなります:resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}); resp.raise_for_status(); data = resp.json(); print(data["items"])。raise_for_status()で4xx/5xxを早期に検知し、成功時のみ本文をパースします。さらに堅牢にするなら、resp.status_codeで分岐し、429ならresp.headers.get("Retry-After")に従って待つ、といった前節までの知識をコードに織り込みます。ここで学ぶべきは、requestsスクリプトの不具合は「認証をheadersで渡せているか」「コードを確認してからjson()しているか」という二点を読めば大半が診断できる、ということです。ライブラリの丸暗記ではなく、HTTPの原則がコード上でどう表れるかを追うのが正攻法です。
| 目的 | requestsの書き方 | よくある誤り |
|---|---|---|
| クエリパラメータを付ける | `requests.get(url, params={"limit":50})` | ヘッダに入れるべき認証を`params=`に置く |
| ヘッダ/認証を渡す | `headers={"Authorization": f"Bearer {t}"}` | `headers=`と`params=`の取り違え |
| JSONボディを送る | `requests.post(url, json=payload)` | `data=`に手動JSON+`Content-Type`付け忘れ |
| 成功確認と本文取得 | `resp.raise_for_status(); resp.json()` | status未確認で`resp.json()`→例外/誤データ |
ひっかけ: 「requestsは4xx/5xxが返ると自動的に例外を投げるので、status_codeを確認しなくてよい」は誤りです——requestsはエラーでも例外を投げず応答オブジェクトを返すため、resp.status_codeの確認かresp.raise_for_status()が必要です。また「認証ヘッダをparams=に入れても同じこと」も誤り=params=はクエリ文字列になり、ヘッダで要求される認証は通らず、トークンをURLに露出させます。
2.5.3この節のまとめ
- 送信は
requests.get(url, headers=, params=, auth=)/requests.post(url, json=)。params==クエリ・headers==ヘッダ(認証)・json==JSONボディ(Content-Type自動)を取り違えない resp.status_codeで成功を確認(またはresp.raise_for_status())してからresp.json()でdict化する。requestsは4xx/5xxで例外を投げないrequestsスクリプトの診断は「認証をheadersで渡せているか」「statusを確認してからjson()しているか」の二点を軸に読む
進捗の記録にはログインが必要です。
理解度チェック
(軽い確認用)Q1. 次の Python コードは Bearer トークンで保護されたAPIを呼ぶが、常に `401` になりトークンがアクセスログのURLに残ってしまう。`resp = requests.get("https://api.example.com/v1/devices", params={"Authorization": f"Bearer {token}"})`。最も適切な修正はどれか。
Q2. 次のコードは「時々 `JSONDecodeError` や `KeyError` で落ちる」と報告された。`resp = requests.get(url, headers=h); data = resp.json(); print(data["items"])`。requestsは4xx/5xxでも例外を投げず応答を返す。堅牢にするための最も適切な修正はどれか。
Q3. JSONボディ `{"name":"sw1","vlan":10}` を作成系エンドポイントへ送りたい。requestsで最も適切かつ `Content-Type: application/json` の付け忘れを避けられる書き方はどれか。

