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

Web APP Python
スポンサーリンク

3日目のゴール

3日目のテーマは
「requests を“使い回せる道具”として設計し、複数のAPIを扱えるようになる」 ことです。

1日目で「とりあえず叩けるようになり」、
2日目で「エラーに強い書き方」を学びました。

3日目では一歩進んで、

同じパターンで別のAPIも叩けるようにする
GETだけでなく、POSTもイメージできるようにする
「APIクライアント関数(またはクラス)」という考え方を持つ

ここまで行けると、
「APIを1個だけ触れる人」から
「APIを道具として横展開できる人」に変わります。


「APIのパターン」を見抜く

どのAPIも、やっていることはだいたい同じ

APIのドキュメントを見ると、
いろんなURLやパラメータが出てきて、
最初は圧倒されがちです。

でも、冷静に分解すると、
やっていることはほぼ同じです。

URLがある
HTTPメソッド(GET / POST / PUT / DELETE など)がある
必要ならクエリパラメータやボディがある
必要ならヘッダー(APIキーなど)がある
返ってくるのはだいたいJSON

1日目・2日目でやったことは、
このうちの「GET+JSON」の部分です。

3日目では、
この「型」を意識しながら、
別のAPIにも同じパターンを当てはめていきます。


複数のエンドポイントを扱うイメージ

同じサービスの中に「いろんな窓口」がある

例えば、1日目・2日目で使った
https://jsonplaceholder.typicode.com には、
こんなエンドポイントがあります。

/todos
/posts
/users

それぞれ、

TODOの情報
ブログ記事っぽい情報
ユーザー情報

を返してくれます。

URLだけ変えて、
同じ get_json 関数を使えば、
どれも同じように扱えます。

import requests

def get_json(url, params=None, timeout=5.0):
    try:
        response = requests.get(url, params=params, timeout=timeout)
    except requests.exceptions.Timeout:
        print("タイムアウトしました。")
        return None
    except requests.exceptions.RequestException as e:
        print("通信エラー:", e)
        return None

    if response.status_code != 200:
        print("エラー応答です。ステータスコード:", response.status_code)
        return None

    try:
        return response.json()
    except ValueError:
        print("JSONとして解釈できませんでした。")
        return None
Python

この「共通の入口」を持っておくと、
あとはURLとパラメータを変えるだけで、
いろんなAPIを触れるようになります。


例題1:ユーザー一覧APIを叩いてみる

「別のエンドポイントでも同じ型で書ける」ことを体感する

ユーザー一覧を取得するAPIを叩いてみます。

def fetch_users():
    url = "https://jsonplaceholder.typicode.com/users"
    data = get_json(url)

    if data is None:
        print("ユーザー一覧の取得に失敗しました。")
        return

    print(f"ユーザーは {len(data)} 人います。")
    for user in data:
        print(f"- {user['id']}: {user['name']} ({user['email']})")
Python

ここで注目してほしいのは、

get_json の使い方は、TODOのときとまったく同じ
変わっているのは URL と、
「返ってきたデータの中から何を表示するか」だけ

という点です。

APIが変わっても、
「叩き方の型」は変わりません。


例題2:記事一覧APIを叩いてみる

同じパターンで別のデータ構造を読む

今度は /posts を叩いてみます。

def fetch_posts(limit=5):
    url = "https://jsonplaceholder.typicode.com/posts"
    data = get_json(url)

    if data is None:
        print("記事一覧の取得に失敗しました。")
        return

    print(f"記事は全部で {len(data)} 件あります。")
    print(f"最初の {limit} 件を表示します。")
    for post in data[:limit]:
        print("-----")
        print(f"ID: {post['id']}")
        print(f"タイトル: {post['title']}")
        print(f"本文: {post['body'][:50]}...")
Python

ここでも、

URLが違う
返ってくるJSONのキーが違う

だけで、
「叩き方の型」は同じです。

この感覚がつかめると、
APIドキュメントを見たときに、

「URLとパラメータと返り値の形だけ分かれば、あとはいつものパターンで書ける」

という安心感が生まれます。


POSTリクエストのイメージを掴む

「データを送る」側のAPI

ここまでの GET は、
「サーバーからデータをもらう」リクエストでした。

POST は、
「サーバーにデータを送る」リクエストです。

例えば、「新しい記事を作成するAPI」があったとします。

POST /posts
ボディに titlebody を送る
成功すると、作成された記事の情報が返ってくる

requests では、
datajson 引数を使って、
送るデータを指定します。

import requests

url = "https://jsonplaceholder.typicode.com/posts"

payload = {
    "title": "テスト投稿",
    "body": "これはテスト投稿の本文です。",
    "userId": 1,
}

response = requests.post(url, json=payload, timeout=5.0)

print("ステータスコード:", response.status_code)
print("レスポンス:", response.json())
Python

ここでの重要ポイントを深掘りします。

requests.post を使うと、HTTPメソッドがPOSTになる
json=payload と書くと、
payload を JSON としてボディに入れて送ってくれる
サーバー側が受け取って、何らかの処理をして、結果を返してくる

実際のサービスでは、
「本当にデータが作成される」ので、
テスト環境やドキュメントをよく読む必要があります。

3日目では、
「GETはもらう、POSTは送る」
というイメージが持てれば十分です。


GETとPOSTをまとめて扱う「APIクライアント関数」

メソッドを引数にしてしまう

2日目で作った get_json を、
少しだけ汎用的にしてみます。

import requests

def request_json(method, url, params=None, json_body=None, headers=None, timeout=5.0):
    try:
        response = requests.request(
            method=method,
            url=url,
            params=params,
            json=json_body,
            headers=headers,
            timeout=timeout,
        )
    except requests.exceptions.Timeout:
        print("タイムアウトしました。")
        return None
    except requests.exceptions.RequestException as e:
        print("通信エラー:", e)
        return None

    if not (200 <= response.status_code < 300):
        print("エラー応答です。ステータスコード:", response.status_code)
        return None

    try:
        return response.json()
    except ValueError:
        print("JSONとして解釈できませんでした。")
        return None
Python

ここでのポイントは、

requests.requestmethod を渡すことで、
GETでもPOSTでも同じ関数で扱えるようにしていること
json_bodyjson= に渡していること
ステータスコードを「200〜299ならOK」としていること

です。

これを使うと、
GETもPOSTも同じ型で書けます。


例題3:GETとPOSTを同じ関数で使う

同じAPIクライアントで、読み取りと作成を行う

def get_todo(todo_id):
    url = f"https://jsonplaceholder.typicode.com/todos/{todo_id}"
    data = request_json("GET", url)

    if data is None:
        print("TODOの取得に失敗しました。")
        return

    print("ID:", data["id"])
    print("タイトル:", data["title"])
    print("完了フラグ:", data["completed"])

def create_post(title, body, user_id):
    url = "https://jsonplaceholder.typicode.com/posts"
    payload = {
        "title": title,
        "body": body,
        "userId": user_id,
    }
    data = request_json("POST", url, json_body=payload)

    if data is None:
        print("投稿の作成に失敗しました。")
        return

    print("作成された投稿:")
    print("ID:", data.get("id"))
    print("タイトル:", data.get("title"))
    print("本文:", data.get("body"))
Python

ここで見てほしいのは、

request_json("GET", ...)
request_json("POST", ...)

という形で、
メソッドだけ変えて同じ関数を使っていることです。

これができると、
APIの種類が増えても、
「叩き方の型」は変わりません。


3日目のミニアプリ:APIメニュー付きコンソールツール

仕様を言葉で整理する

コンソール上で動く「APIお試しツール」を作ります。

メニューを表示する
1を選ぶと TODO を1件取得
2を選ぶと ユーザー一覧を取得
3を選ぶと 記事を数件取得
0で終了

APIの叩き方は全部「同じ型」で書きます。


コード全体

import requests

def request_json(method, url, params=None, json_body=None, timeout=5.0):
    try:
        response = requests.request(
            method=method,
            url=url,
            params=params,
            json=json_body,
            timeout=timeout,
        )
    except requests.exceptions.Timeout:
        print("タイムアウトしました。")
        return None
    except requests.exceptions.RequestException as e:
        print("通信エラー:", e)
        return None

    if not (200 <= response.status_code < 300):
        print("エラー応答です。ステータスコード:", response.status_code)
        return None

    try:
        return response.json()
    except ValueError:
        print("JSONとして解釈できませんでした。")
        return None

def fetch_todo():
    todo_id_str = input("TODOのIDを入力してください(例: 1): ").strip()
    if not todo_id_str.isdigit():
        print("数字を入力してください。")
        return

    todo_id = int(todo_id_str)
    url = f"https://jsonplaceholder.typicode.com/todos/{todo_id}"
    data = request_json("GET", url)

    if data is None:
        print("TODOの取得に失敗しました。")
        return

    print("----- TODO -----")
    print("ID:", data["id"])
    print("タイトル:", data["title"])
    print("完了フラグ:", data["completed"])

def fetch_users():
    url = "https://jsonplaceholder.typicode.com/users"
    data = request_json("GET", url)

    if data is None:
        print("ユーザー一覧の取得に失敗しました。")
        return

    print("----- ユーザー一覧 -----")
    for user in data:
        print(f"{user['id']}: {user['name']} ({user['email']})")

def fetch_posts():
    url = "https://jsonplaceholder.typicode.com/posts"
    data = request_json("GET", url)

    if data is None:
        print("記事一覧の取得に失敗しました。")
        return

    print("----- 記事(最初の5件) -----")
    for post in data[:5]:
        print("ID:", post["id"])
        print("タイトル:", post["title"])
        print("本文:", post["body"][:50], "...")
        print("-----")

def main():
    while True:
        print()
        print("APIお試しツール")
        print("1: TODOを1件取得")
        print("2: ユーザー一覧を取得")
        print("3: 記事を5件取得")
        print("0: 終了")
        choice = input("番号を選んでください: ").strip()

        if choice == "1":
            fetch_todo()
        elif choice == "2":
            fetch_users()
        elif choice == "3":
            fetch_posts()
        elif choice == "0":
            print("終了します。")
            break
        else:
            print("不正な入力です。")

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

ここには、3日目で押さえたい要素が全部入っています。

共通の request_json で、
GETリクエストとエラー処理を一元管理している。
各機能(TODO・ユーザー・記事)は、
「URLと表示ロジック」だけを書けばよくなっている。


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

「APIの叩き方を“型”として持つ」と世界が一気に楽になる

今日いちばん大事なのは、

APIごとに毎回ゼロから書かない
自分なりの「APIクライアント関数(request_json)」を持つ
URL・パラメータ・メソッド・表示ロジックだけを差し替える

という発想です。

技術的なキーワードをまとめると、

複数エンドポイントを同じ関数で扱う
requests.request(method=...) でGET/POSTを統一する
JSONレスポンスを辞書・リストとして扱うのはどれも同じ
「URLと返り値の形が分かれば怖くない」状態になる

ここまで来たあなたは、
もう「APIを触れる人」ではなく、
「APIを設計して使い回せる人」 の入り口に立っています。

4日目以降は、
ここで作ったAPIクライアントを
tkinter のボタンイベントと組み合わせて、
「ボタンを押したらAPIを叩いて、結果を画面に表示する」
という、いよいよ“GUI付きAPIアプリ”に進んでいきましょう。

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