Instiq
第2章 · APIの理解と利用·v1.0.0·更新 2026/7/20·読了目安 約16分

変更要約: 初版

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-Typeheaders=の辞書で渡す。この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()を使う。requests4xx/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()`→例外/誤データ
注意

ひっかけ:requests4xx/5xxが返ると自動的に例外を投げるので、status_codeを確認しなくてよい」は誤りです——requestsエラーでも例外を投げず応答オブジェクトを返すため、resp.status_codeの確認かresp.raise_for_status()が必要です。また「認証ヘッダをparams=に入れても同じこと」も誤り=params=クエリ文字列になり、ヘッダで要求される認証は通らず、トークンをURLに露出させます。

`requests.get/post`の引数と`status_code`/`json()`確認の図。
requestsスクリプトの欠陥を診断する

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` の付け忘れを避けられる書き方はどれか。

理解度を確認第2章「APIの理解と利用」の問題を解く