Python講座 / HTTP APIとJSON応答・通信エラーを扱う
HTTP APIはリクエストを受けてステータスとデータを返す仕組みです。Pythonのクライアントでは、通信の成功、待ち時間の上限、応答の大きさ、JSONの構造と値をそれぞれ確認します。
通信方式・場所・形式を区別する
HTTPはリクエストと応答の通信規約、URLはリソースを特定するアドレス、JSONは本文のデータ形式の一つです。成功ステータスでも、アプリケーションが期待するデータとは限りません。外部サービスでは公式のHTTPS、認証、利用制限にも従います。
この実習は応答を管理できるローカルサーバーを使います。クライアントの処理を学ぶためのもので、本番サーバーの配備手順ではありません。
JSONの型検証と保存は、JSONデータを変換して保存するで扱う規則とつながります。
応答ファイルとローカルサーバーを準備する
新しいフォルダーへexpenses.jsonを保存します。
[{"id":"e1","name":"coffee","amount":3500},{"id":"e2","name":"lunch","amount":8000}]
一つ目のターミナルでそのフォルダーへ移動し、実行します。
python -m http.server 8000 --bind 127.0.0.1
127.0.0.1へのバインドは同じPCからの接続に限ります。8000番が使用中なら別のポートを選び、クライアントのURLも合わせます。
クライアント全体を保存して実行する
fetch_expenses.pyへ保存します。追加パッケージは不要です。
import json
import sys
from urllib.request import urlopen
from urllib.error import HTTPError, URLError
url = sys.argv[1]
try:
with urlopen(url, timeout=5) as response:
if response.status != 200:
raise ValueError("unexpected status")
raw = response.read(1_000_001)
if len(raw) > 1_000_000:
raise ValueError("response too large")
data = json.loads(raw.decode("utf-8"))
except (HTTPError, URLError, TimeoutError, UnicodeError, ValueError) as error:
raise SystemExit(f"request failed: {type(error).__name__}")
if not isinstance(data, list):
raise SystemExit("expected a list")
total = 0
for row in data:
if not isinstance(row, dict) or type(row.get("amount")) is not int or row["amount"] < 0:
raise SystemExit("invalid record")
total += row["amount"]
print("records:", len(data))
print("total:", total)
仮想環境を選んだ二つ目のターミナルで実行します。
python fetch_expenses.py http://127.0.0.1:8000/expenses.json
records: 2、total: 11500が予想結果です。終了時は一つ目のターミナルでCtrl+Cを押し、サーバーを止めます。
通信失敗と不正なデータを区別する
存在しないパスではHTTPError、接続失敗ではURLErrorなどが起こります。timeoutは個々の待ちを制限し、処理全体が必ずその秒数で終わる保証ではありません。大きすぎる応答、UTF-8やJSONの不正、型や金額の不正も別に拒否します。
ファイル名を誤記する、金額を文字列にする、サーバーを止める、という条件を一つずつ試して元へ戻します。再試行には回数・間隔の制限と副作用の検討が必要です。支払いなどを無条件で再送しないでください。認証情報をコード・URL・ログへ残さず管理します。API収集の実習では検証後に取引単位で保存します。
HTTPErrorはエラーのHTTP応答、URLErrorは名前解決や接続などの通信失敗を表します。応答を受けてもサイズ・JSON・フィールド検証で失敗する場合があります。成功らしいデータに置き換えず、原因を区別して記録します。再試行は冪等性、回数、待ち時間の方針を決めてから追加します。




