Bài 16. Gọi API web với requests và httpx

Rất nhiều dịch vụ (thời tiết, tỷ giá, mạng xã hội, AI) cung cấp API. Bài này dạy gửi yêu cầu HTTP, xử lý JSON, tham số, header, lỗi và giữ khóa API an toàn.

45 phútTrung cấp
Bạn sẽ học được
  • Hiểu HTTP: phương thức, mã trạng thái, header
  • Gửi GET/POST bằng requests
  • Xử lý lỗi, timeout, thử lại
  • Bảo vệ khóa API bằng biến môi trường
Thuật ngữ cần biết
API
Giao diện để chương trình trao đổi dữ liệu.
Endpoint
Địa chỉ URL của một chức năng API.
Status code
Mã kết quả: 200 thành công, 404 không tìm thấy, 500 lỗi máy chủ.
API key
Khóa xác thực khi gọi API.

Khái niệm và lý thuyết

Một lời gọi API gồm: phương thức (GET lấy, POST tạo, PUT/PATCH sửa, DELETE xóa), URL, header (định dạng, xác thực), body (dữ liệu gửi đi). Máy chủ trả về mã trạng thái và thân phản hồi, thường là JSON.

MãÝ nghĩa
2xxThành công (200 OK, 201 Created)
4xxLỗi phía người gọi (400 sai dữ liệu, 401 chưa xác thực, 404, 429 gọi quá nhiều)
5xxLỗi phía máy chủ

GET với requests

import requests
r = requests.get(
    "https://api.open-meteo.com/v1/forecast",
    params={"latitude": 21.33, "longitude": 103.91, "current": "temperature_2m"},  # Sơn La
    timeout=10,
)
r.raise_for_status()                  # ném lỗi nếu 4xx/5xx
du_lieu = r.json()
print("Nhiệt độ Sơn La:", du_lieu["current"]["temperature_2m"], "°C")

POST và xác thực

import os
API_KEY = os.environ["MY_API_KEY"]    # đọc từ biến môi trường, không ghi thẳng vào mã
r = requests.post(
    "https://httpbin.org/post",
    json={"ten": "An", "diem": 9},
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=10,
)
print(r.status_code, r.json()["json"])

Xử lý lỗi

from requests.exceptions import RequestException
def lay_json(url, lan_thu=3):
    for i in range(lan_thu):
        try:
            r = requests.get(url, timeout=5)
            r.raise_for_status()
            return r.json()
        except RequestException as e:
            print(f"Lần {i + 1} lỗi: {e}")
    return None

httpx: bất đồng bộ

import asyncio, httpx
async def main():
    async with httpx.AsyncClient(timeout=10) as client:
        urls = [f"https://jsonplaceholder.typicode.com/posts/{i}" for i in range(1, 6)]
        kq = await asyncio.gather(*(client.get(u) for u in urls))
        print([r.json()["title"][:20] for r in kq])
asyncio.run(main())

httpx có API gần giống requests nhưng hỗ trợ async, gọi song song nhiều API nhanh hơn nhiều (chi tiết async ở Bài 19).

Mẹo hay

Thử API trước bằng trình duyệt hoặc tiện ích REST Client của VS Code để biết cấu trúc JSON, rồi mới viết mã.

Lưu ý

Luôn đặt timeout; không có timeout, chương trình có thể treo mãi khi máy chủ không phản hồi. Tôn trọng giới hạn số lần gọi (rate limit) của API.

Thực hành
  1. Lấy nhiệt độ hiện tại của 5 tỉnh Tây Bắc từ Open-Meteo, in bảng.
  2. Lấy danh sách bài viết từ jsonplaceholder, lưu ra JSON.
  3. Viết hàm có thử lại khi lỗi, dùng thời gian chờ tăng dần.
  4. Dùng httpx gọi song song 20 URL và so sánh thời gian với requests.
Tóm tắt bài học
  • HTTP: phương thức, URL, header, body, mã trạng thái.
  • requests cho đồng bộ, httpx cho cả async.
  • raise_for_status, timeout, thử lại để chắc chắn.
  • Khóa API đặt trong biến môi trường.