Python | 1 日 120 分 × 7 日アプリ学習:API取得アプリ(requests使用)(中級編)

Web APP Python
スポンサーリンク

6日目のゴール

6日目のテーマは
「“本物のAPIドキュメント”を読んで、自分でエンドポイントを差し替えられるようになる」 ことです。

ここまでであなたは、

requests でGET・POSTを送れる
エラー処理付きの request_json を書ける
JSONのネストやリストを読める
API層とアプリ層を分けて設計できる

というところまで来ています。

6日目では一歩進んで、

「サンプルAPI」から一歩外に出て、
自分で別のAPIに差し替える力

を鍛えます。

今日は、
「APIドキュメントの読み方」と
「エンドポイントを差し替えるときの考え方」にフォーカスします。


「APIドキュメントを読む」という新しい壁

何が書いてあるのかをざっくり分解する

本物の外部APIを使うとき、必ず出てくるのが「APIドキュメント」です。
最初に見ると、だいたいこう感じます。

項目が多すぎる
英語が多くてつらい
どこから読めばいいか分からない

でも、構造としてはそんなに複雑ではありません。
だいたい、次のような情報が載っています。

どのURLにアクセスするか(エンドポイント)
どのHTTPメソッドを使うか(GET / POST など)
必要なパラメータは何か(クエリ・ボディ)
認証(APIキーやトークン)が必要か
レスポンスのJSONの例

6日目でやりたいのは、
この中から「requestsを書くのに必要な部分だけを抜き出す目」を持つことです。


「エンドポイント」と「ベースURL」を意識する

BASE_URL とパスを分けて考える

APIドキュメントには、よくこんな書き方が出てきます。

ベースURL
https://api.example.com

エンドポイント
GET /v1/weather
GET /v1/forecast

これを見たときに、Python側ではこう分解します。

ベースURLを BASE_URL として一か所にまとめる
エンドポイントは BASE_URL にパスを足して作る

という形です。

例えば、こうです。

BASE_URL = "https://api.example.com"

def build_url(path: str) -> str:
    return f"{BASE_URL}{path}"
Python

そして、エンドポイントごとにこう書きます。

url = build_url("/v1/weather")
Python

ここでの重要ポイントは、

「URLをベタ書きしない」
「ベースURLとパスを分ける」

という癖をつけることです。

これをやっておくと、
ベースURLが変わったときに、
一か所を直すだけで済みます。


クエリパラメータをドキュメントから写経する

「必須」「任意」を見分ける

APIドキュメントには、よくこんな表が出てきます。

q:都市名(必須)
units:単位(任意、デフォルトは metric)
lang:言語(任意)

これを見たら、Python側では「params の辞書」に落とし込みます。

params = {
    "q": "Tokyo",
    "units": "metric",
    "lang": "ja",
}
Python

そして、requests ではこう使います。

import requests

url = build_url("/v1/weather")
result = requests.get(url, params=params, timeout=5.0)
Python

ここでの本質は、

ドキュメントの「パラメータ一覧」を見たら、
「これは params の辞書に写せばいいんだな」と変換できること

です。

必須パラメータは必ず入れる。
任意パラメータは、必要なものだけ選んで入れる。

この「写経力」が付くと、
どんなAPIでも怖くなくなります。


認証(APIキー)をどう扱うかのイメージ

コードにベタ書きしない、という感覚だけ持つ

多くの実用APIは、
「APIキー」や「トークン」が必要です。

ドキュメントには、だいたいこう書いてあります。

ヘッダーに Authorization: Bearer YOUR_TOKEN を付けてください
または
クエリパラメータに apikey=YOUR_KEY を付けてください

6日目では、
実際のキーは使わなくてもいいので、
「どこにどう渡すか」のイメージだけ持ちましょう。

ヘッダーの場合はこうです。

headers = {
    "Authorization": "Bearer YOUR_API_TOKEN",
}
Python

クエリパラメータの場合はこうです。

params = {
    "apikey": "YOUR_API_KEY",
    "q": "Tokyo",
}
Python

そして、request_json に渡します。

from api_client import request_json

def fetch_weather(city: str):
    url = build_url("/v1/weather")
    params = {"q": city, "units": "metric", "lang": "ja", "apikey": "YOUR_API_KEY"}
    result = request_json("GET", url, params=params)

    if not result["ok"]:
        return None, result["message"]

    return result["data"], None
Python

ここでの超重要ポイントは、

APIキーを「API層の中に閉じ込める」
アプリ層には見せない

という設計の感覚です。

本番では、さらに一歩進んで
環境変数や設定ファイルから読み込むのですが、
6日目では「ベタ書きしない方がいいんだな」くらいでOKです。


「別のAPIに差し替える」練習

これまでの jsonplaceholder を「天気API風」に置き換える

ここまでの練習では、
https://jsonplaceholder.typicode.com を使ってきました。

6日目では、
「もしこれが天気APIだったら?」というつもりで、
エンドポイントだけ差し替える練習をします。

例えば、こういう設計にしてみます。

ベースURL
https://api.example.com

エンドポイント
現在の天気:GET /v1/weather
予報:GET /v1/forecast

パラメータ
q:都市名(必須)
units:単位(任意)
lang:言語(任意)

これをコードに落とすと、こうなります。

# api_service_weather.py

from api_client import request_json

BASE_URL = "https://api.example.com"

def build_url(path: str) -> str:
    return f"{BASE_URL}{path}"

def fetch_current_weather(city: str, lang: str = "ja"):
    url = build_url("/v1/weather")
    params = {
        "q": city,
        "units": "metric",
        "lang": lang,
        # "apikey": "YOUR_API_KEY",  # 実際のAPIならここにキーを入れる
    }
    result = request_json("GET", url, params=params)

    if not result["ok"]:
        return None, result["message"]

    return result["data"], None

def fetch_forecast(city: str, lang: str = "ja"):
    url = build_url("/v1/forecast")
    params = {
        "q": city,
        "units": "metric",
        "lang": lang,
        # "apikey": "YOUR_API_KEY",
    }
    result = request_json("GET", url, params=params)

    if not result["ok"]:
        return None, result["message"]

    return result["data"], None
Python

ここで見てほしいのは、

ベースURLが変わっても、
request_json の使い方はまったく同じ

という点です。

「どのAPIを叩くか」は、
BASE_URL と path と params を変えるだけで表現できます。


レスポンスの「必要な部分だけ」を決める

天気APIを想像して、欲しい情報を選ぶ

天気APIのレスポンスは、だいたいこんな感じです(イメージ)。

現在の天気
都市名
気温
体感温度
湿度
天気の説明(晴れ、曇りなど)

これを Python で扱うとき、
「全部をそのまま print する」のではなく、
欲しい情報だけを選んで整形します。

例えば、こういう関数を用意します。

def format_current_weather(data: dict) -> str:
    city = data.get("name", "不明な場所")
    main = data.get("main", {})
    weather_list = data.get("weather", [])

    temp = main.get("temp")
    feels = main.get("feels_like")
    humidity = main.get("humidity")

    if weather_list:
        description = weather_list[0].get("description", "")
    else:
        description = ""

    lines = []
    lines.append(f"場所: {city}")
    if temp is not None:
        lines.append(f"気温: {temp} ℃(体感 {feels} ℃)")
    if humidity is not None:
        lines.append(f"湿度: {humidity} %")
    if description:
        lines.append(f"天気: {description}")

    return "\n".join(lines)
Python

ここでの重要ポイントは、

APIの生データをそのまま見せるのではなく、
「アプリとして見せたい形」に一度変換していること

です。

この「整形関数」を用意しておくと、
コンソールでもGUIでも、
同じ関数を使って表示できます。


6日目のミニアプリ:都市名から天気情報を取得(疑似版)

仕様を言葉で整理する

都市名を入力する。
API層の fetch_current_weather を呼ぶ。
成功したら format_current_weather で整形して表示する。
失敗したらエラーメッセージを表示する。

実際の天気APIの代わりに、
ここでは「天気API風のダミーデータ」を使って流れを確認します。


ダミーAPI版のコード

# api_client_dummy.py
# 実際の requests の代わりに、ダミーのレスポンスを返す版

def request_json(method, url, params=None, json_body=None, headers=None, timeout=5.0):
    # 本当はここで requests.request(...) を呼ぶが、
    # 学習用に「天気API風のダミーデータ」を返す
    city = params.get("q", "Unknown") if params else "Unknown"

    data = {
        "name": city,
        "main": {
            "temp": 22.5,
            "feels_like": 21.0,
            "humidity": 60,
        },
        "weather": [
            {"description": "晴れ(ダミーデータ)"}
        ],
    }

    return {
        "ok": True,
        "error_type": None,
        "status_code": 200,
        "data": data,
    }
Python
# api_service_weather_dummy.py

from api_client_dummy import request_json

BASE_URL = "https://api.example.com"

def build_url(path: str) -> str:
    return f"{BASE_URL}{path}"

def fetch_current_weather(city: str, lang: str = "ja"):
    url = build_url("/v1/weather")
    params = {
        "q": city,
        "units": "metric",
        "lang": lang,
    }
    result = request_json("GET", url, params=params)

    if not result["ok"]:
        return None, result["message"]

    return result["data"], None
Python
# app_weather_console.py

from api_service_weather_dummy import fetch_current_weather

def format_current_weather(data: dict) -> str:
    city = data.get("name", "不明な場所")
    main = data.get("main", {})
    weather_list = data.get("weather", [])

    temp = main.get("temp")
    feels = main.get("feels_like")
    humidity = main.get("humidity")

    if weather_list:
        description = weather_list[0].get("description", "")
    else:
        description = ""

    lines = []
    lines.append(f"場所: {city}")
    if temp is not None:
        lines.append(f"気温: {temp} ℃(体感 {feels} ℃)")
    if humidity is not None:
        lines.append(f"湿度: {humidity} %")
    if description:
        lines.append(f"天気: {description}")

    return "\n".join(lines)

def main():
    print("天気情報取得アプリ(ダミーAPI版)")
    city = input("都市名を入力してください: ").strip()

    if city == "":
        print("都市名が空です。終了します。")
        return

    data, error = fetch_current_weather(city)

    if error is not None or data is None:
        print("取得に失敗しました。")
        print("詳細:", error)
        return

    text = format_current_weather(data)
    print()
    print("=== 結果 ===")
    print(text)

if __name__ == "__main__":
    main()
Python

このミニアプリで、6日目のポイントが全部体験できます。

API層(fetch_current_weather)は、
「どのURLに、どんなパラメータでアクセスするか」を知っている。
アプリ層(main)は、
「都市名を聞いて、結果を整形して表示する」ことだけを考えている。
整形関数(format_current_weather)は、
「生のJSONを、人間にとって読みやすい文章に変換する」役割を持っている。


6日目で絶対に押さえてほしい本質

「APIドキュメントを“requestsの材料”として読む」

今日いちばん大事なのは、
APIドキュメントを見たときに、こう変換できることです。

ベースURL → BASE_URL
エンドポイント → build_url(“/path”)
パラメータ一覧 → params の辞書
認証の説明 → headers や params にAPIキーを足す
レスポンス例 → format_xxx で整形する材料

そして、コードの構造としては、

request_json(共通クライアント)
fetch_xxx(このアプリ専用のAPI層)
format_xxx(表示用の整形)
main(入出力とアプリの流れ)

という役割分担を意識することです。

ここまで来たあなたは、
もう「サンプルAPIで遊んでいる人」ではなく、
「APIドキュメントを読んで、自分でエンドポイントを差し替えられる人」 になっています。

7日目では、
今日の「天気API風アプリ」の構造をそのまま、
tkinter のGUIに乗せていきます。
ボタンを押したら都市名を読み取り、API層を呼び、
結果をテキストエリアに表示する——
そんな“中級者らしいAPI取得アプリ”の完成形に持っていきましょう。

タイトルとURLをコピーしました