PythonPython 기초강의 10개 중 9번째난이도 입문

HTTP 요청 — 외부 API 호출하기

발행 읽는 시간 약 2 분

  • Python
  • HTTP
  • API
  • requests
  • JSON
  • REST

강의 소개

requests와 httpx로 REST API를 호출하고, JSON 응답을 처리하는 방법을 배웁니다. 헤더 설정, 인증, 에러 처리까지 실전 API 연동에 필요한 모든 것을 익힙니다.

파이썬이 인터넷과 대화하는 방법#

날씨 API, 주식 데이터, OpenAI API 모두 HTTP를 통해 데이터를 주고받습니다.

Diagram · Mermaid

requests 설치와 기본 사용#

Bash
pip install requests
Python
import requests

# GET 요청: 데이터 조회
response = requests.get("https://api.github.com/users/octocat")

print(response.status_code)   # 200 (성공)
print(response.headers["content-type"])

# JSON 응답 파싱
data = response.json()
print(data["name"])    # The Octocat
print(data["bio"])     # 프로필 소개

HTTP 상태 코드#

코드의미
200성공
201생성 성공
400잘못된 요청
401인증 필요
403권한 없음
404찾을 수 없음
429요청 한도 초과
500서버 오류

GET 요청: 쿼리 파라미터#

Python
import requests

# URL에 직접 쿼리스트링 쓰는 대신 params 사용
response = requests.get(
    "https://api.example.com/search",
    params={
        "query": "파이썬",
        "limit": 10,
        "lang": "ko"
    }
)
# 실제 요청: https://api.example.com/search?query=파이썬&limit=10&lang=ko

print(response.url)   # 완성된 URL 확인
data = response.json()

POST 요청: 데이터 전송#

Python
import requests

# JSON 데이터 전송
response = requests.post(
    "https://api.example.com/users",
    json={                          # json= 파라미터: 자동으로 Content-Type: application/json
        "name": "김철수",
        "email": "kim@example.com"
    }
)

if response.status_code == 201:
    created = response.json()
    print(f"생성됨: {created['id']}")

헤더와 인증#

Python
import requests
import os

API_KEY = os.getenv("MY_API_KEY")

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
    "User-Agent": "MyApp/1.0"
}

response = requests.get(
    "https://api.example.com/protected",
    headers=headers
)

에러 처리#

Python
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError

def fetch_data(url: str) -> dict | None:
    try:
        response = requests.get(url, timeout=10)  # 10초 타임아웃
        response.raise_for_status()  # 4xx, 5xx면 예외 발생
        return response.json()
        
    except Timeout:
        print(f"요청 시간 초과: {url}")
    except ConnectionError:
        print("네트워크 연결 실패")
    except requests.HTTPError as e:
        print(f"HTTP 오류 {e.response.status_code}: {url}")
    except RequestException as e:
        print(f"요청 실패: {e}")
    
    return None

data = fetch_data("https://api.github.com/users/octocat")
if data:
    print(data["name"])

Session: 연결 재사용#

같은 서버에 여러 번 요청할 때 Session을 쓰면 효율적입니다.

Python
import requests

session = requests.Session()
session.headers.update({
    "Authorization": f"Bearer {API_KEY}",
    "Accept": "application/json"
})

# 헤더를 매번 설정하지 않아도 됨
r1 = session.get("https://api.example.com/users")
r2 = session.get("https://api.example.com/products")
r3 = session.post("https://api.example.com/orders", json={"item_id": 1})

session.close()  # 또는 with 구문 사용

httpx: 비동기 HTTP 클라이언트#

FastAPI 등 비동기 환경에서는 httpx를 씁니다.

Bash
pip install httpx
Python
import httpx
import asyncio

async def fetch_multiple():
    async with httpx.AsyncClient() as client:
        # 동시에 여러 요청
        tasks = [
            client.get(f"https://api.example.com/user/{i}")
            for i in range(1, 6)
        ]
        responses = await asyncio.gather(*tasks)
        
        return [r.json() for r in responses]

results = asyncio.run(fetch_multiple())

실전: 날씨 API 연동#

Python
import requests
import os

def get_weather(city: str) -> dict:
    """OpenWeatherMap API로 날씨 조회"""
    API_KEY = os.getenv("OPENWEATHER_API_KEY")
    
    response = requests.get(
        "https://api.openweathermap.org/data/2.5/weather",
        params={
            "q": city,
            "appid": API_KEY,
            "units": "metric",  # 섭씨
            "lang": "kr"
        },
        timeout=5
    )
    response.raise_for_status()
    
    data = response.json()
    return {
        "city": data["name"],
        "temp": data["main"]["temp"],
        "feels_like": data["main"]["feels_like"],
        "description": data["weather"][0]["description"],
        "humidity": data["main"]["humidity"]
    }

try:
    weather = get_weather("Seoul")
    print(f"{weather['city']}: {weather['temp']}°C ({weather['description']})")
except requests.HTTPError as e:
    print(f"API 오류: {e}")

실전: GitHub API로 레포지토리 목록 조회#

Python
import requests

def get_repos(username: str, token: str = None) -> list:
    headers = {}
    if token:
        headers["Authorization"] = f"token {token}"
    
    all_repos = []
    page = 1
    
    while True:
        response = requests.get(
            f"https://api.github.com/users/{username}/repos",
            headers=headers,
            params={"per_page": 100, "page": page}
        )
        response.raise_for_status()
        
        repos = response.json()
        if not repos:
            break
        
        all_repos.extend(repos)
        page += 1
    
    return sorted(all_repos, key=lambda r: r["stargazers_count"], reverse=True)

repos = get_repos("torvalds")
for repo in repos[:5]:
    print(f"⭐ {repo['stargazers_count']:,} | {repo['name']}")

정리#

메서드용도파라미터
requests.get(url)데이터 조회params={}
requests.post(url)데이터 생성json={}
requests.put(url)데이터 수정json={}
requests.delete(url)데이터 삭제-
response.json()JSON 파싱-
response.raise_for_status()오류 상태 자동 예외-
httpx.AsyncClient비동기 HTTPasync with

다음 편에서는 최종 프로젝트 — 지금까지 배운 파이썬 개념을 모두 활용해 실용적인 도구를 만듭니다.

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.