🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

requests로 API 호출하기 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 17. · 7 Views

requests로 API 호출하기 완벽 가이드

Python의 requests 라이브러리를 활용한 API 호출 방법을 실무 중심으로 배웁니다. 기본 설치부터 에러 핸들링까지, 초급 개발자도 쉽게 따라할 수 있는 실전 가이드입니다.


목차

  1. requests 라이브러리 설치
  2. GET 요청 보내기
  3. 응답 상태 코드 확인
  4. response.json() 파싱
  5. 쿼리 파라미터 전달
  6. 헤더와 인증 처리
  7. 에러 핸들링

1. requests 라이브러리 설치

입사 첫날, 김개발 씨는 팀장님으로부터 간단한 업무를 받았습니다. "날씨 API에서 데이터를 가져와서 화면에 표시해주세요." 하지만 Python으로 어떻게 API를 호출하는지 막막했습니다.

requests는 Python에서 HTTP 요청을 보내는 가장 인기 있는 라이브러리입니다. 마치 우체부가 편지를 배달하듯이, 서버에 요청을 보내고 응답을 받아옵니다.

복잡한 HTTP 통신을 간단한 코드 몇 줄로 처리할 수 있습니다.

다음 코드를 살펴봅시다.

# pip를 사용한 requests 설치
# 터미널에서 실행하세요
pip install requests

# 설치 확인
import requests
print(requests.__version__)  # 설치된 버전 확인

# 이제 requests를 사용할 준비가 완료되었습니다!

김개발 씨는 선배 개발자 박시니어 씨에게 도움을 요청했습니다. "API 호출이 처음인데요, 어떻게 시작해야 할까요?" 박시니어 씨가 웃으며 대답했습니다.

"걱정하지 마세요. Python에는 requests라는 아주 훌륭한 라이브러리가 있어요." requests 라이브러리란 무엇일까요? 쉽게 비유하자면, requests는 마치 우체국과 같습니다.

여러분이 편지(요청)를 쓰면 우체부가 그 편지를 목적지(서버)에 전달하고, 답장(응답)을 다시 가져다줍니다. 이처럼 requests도 서버와의 통신을 대신 처리해주는 역할을 합니다.

왜 requests를 사용할까요? Python에는 기본적으로 urllib이라는 HTTP 라이브러리가 내장되어 있습니다. 하지만 urllib은 사용법이 복잡하고 코드가 길어집니다.

예를 들어 간단한 GET 요청 하나를 보내려고 해도 여러 줄의 코드가 필요합니다. 반면 requests는 정말 직관적입니다.

"이 URL에서 데이터를 가져와줘"라는 의도를 코드 한 줄로 표현할 수 있습니다. 이런 간결함 덕분에 전 세계 Python 개발자들이 가장 사랑하는 라이브러리가 되었습니다.

설치는 어떻게 할까요? requests는 Python 기본 라이브러리가 아니기 때문에 별도로 설치해야 합니다. 하지만 걱정하지 마세요.

설치 과정은 정말 간단합니다. 터미널이나 명령 프롬프트를 열고 "pip install requests"라고 입력하면 됩니다.

pip는 Python 패키지를 관리하는 도구입니다. 마치 앱 스토어에서 앱을 다운로드하듯이, pip를 통해 필요한 라이브러리를 설치할 수 있습니다.

설치가 완료되면 Python 코드에서 "import requests"로 불러올 수 있습니다. 이제 준비가 끝났습니다!

버전 확인하기 설치가 제대로 되었는지 확인하고 싶다면 requests의 버전을 출력해보세요. "requests.version"을 프린트하면 현재 설치된 버전이 표시됩니다.

보통 "2.31.0"과 같은 형태로 나타납니다. 가상환경 사용하기 실무에서는 프로젝트마다 독립적인 가상환경을 만들어 사용하는 것이 좋습니다.

마치 각 프로젝트마다 별도의 작업공간을 만드는 것과 같습니다. 이렇게 하면 프로젝트 간 라이브러리 버전 충돌을 방지할 수 있습니다.

가상환경을 만들려면 "python -m venv myenv" 명령어를 사용하고, 활성화한 후 requests를 설치하면 됩니다. 프로젝트가 커질수록 이런 환경 관리의 중요성을 실감하게 됩니다.

설치 후 첫걸음 김개발 씨는 박시니어 씨의 설명을 듣고 바로 requests를 설치했습니다. "생각보다 정말 간단하네요!" requests를 설치했다면 이제 본격적으로 API를 호출할 준비가 된 것입니다.

다음 단계에서는 실제로 서버에 요청을 보내는 방법을 배워보겠습니다.

실전 팁

💡 - 프로젝트마다 가상환경을 만들어 requests를 설치하세요

  • pip install requests==2.31.0 처럼 특정 버전을 지정할 수도 있습니다

2. GET 요청 보내기

requests를 설치한 김개발 씨는 이제 실제로 API를 호출해야 합니다. "GET 요청이 뭔가요?"라고 물었더니 박시니어 씨가 "서버에서 데이터를 가져오는 가장 기본적인 방법"이라고 설명해줍니다.

GET 요청은 서버에서 데이터를 조회할 때 사용하는 HTTP 메서드입니다. 마치 도서관에서 책을 빌리듯이, 서버에 "이 정보를 보여주세요"라고 요청하는 것입니다.

requests.get() 함수 하나로 간단하게 구현할 수 있습니다.

다음 코드를 살펴봅시다.

import requests

# JSONPlaceholder의 무료 테스트 API 사용
url = "https://jsonplaceholder.typicode.com/posts/1"

# GET 요청 보내기
response = requests.get(url)

# 응답 내용 출력
print(response.text)  # 원시 텍스트 형태
print(response.json())  # JSON 형태로 파싱

# 응답 데이터에서 원하는 값 추출
data = response.json()
print(f"제목: {data['title']}")

김개발 씨는 드디어 첫 API 호출을 시도하게 되었습니다. 손이 약간 떨렸지만, 박시니어 씨가 옆에서 차근차근 알려주었습니다.

GET 요청이란 무엇일까요? 웹 세계에는 여러 종류의 HTTP 메서드가 있습니다. 그중 GET은 가장 기본적이고 자주 사용되는 메서드입니다.

쉽게 비유하자면, GET은 마치 식당에서 메뉴판을 보는 것과 같습니다. 아무것도 바꾸지 않고, 단지 정보를 확인하는 행위입니다.

반대로 POST는 주문을 하는 것과 같습니다. 서버에 새로운 데이터를 생성하거나 변경을 요청하죠.

하지만 지금은 GET에 집중해봅시다. 어떻게 사용할까요? requests 라이브러리를 사용하면 GET 요청은 정말 간단합니다.

"requests.get(url)" 딱 이것만 있으면 됩니다. url 자리에 데이터를 가져올 주소를 넣으면 끝입니다.

예제에서는 JSONPlaceholder라는 무료 테스트 API를 사용했습니다. 이 서비스는 개발 연습용으로 만들어진 가짜 데이터를 제공합니다.

실제 서비스에 부담을 주지 않고 마음껏 테스트할 수 있죠. response 객체 이해하기 requests.get()을 실행하면 response 객체가 반환됩니다.

이 객체에는 서버가 보내준 모든 정보가 담겨 있습니다. 마치 우편 배달부가 가져온 소포와 같습니다.

response.text를 프린트하면 응답 내용을 문자열 형태로 볼 수 있습니다. JSON 형태의 데이터라면 response.json()을 사용하는 것이 더 편리합니다.

이 메서드는 JSON 문자열을 자동으로 Python 딕셔너리로 변환해줍니다. 데이터 추출하기 response.json()으로 얻은 데이터는 일반적인 Python 딕셔너리입니다.

따라서 딕셔너리 문법을 그대로 사용할 수 있습니다. 예를 들어 "data['title']"처럼 키를 사용해 원하는 값을 꺼낼 수 있습니다.

예제의 API는 블로그 포스트 데이터를 반환합니다. title, body, userId 같은 필드가 포함되어 있죠.

실제 프로젝트에서는 이렇게 받아온 데이터를 가공해서 사용자에게 보여주거나 데이터베이스에 저장합니다. 동기 vs 비동기 requests.get()은 동기적으로 동작합니다.

즉, 서버의 응답을 받을 때까지 코드 실행이 멈춥니다. 마치 전화 통화를 하면서 상대방의 대답을 기다리는 것과 같습니다.

빠른 API라면 문제없지만, 응답이 느린 서버라면 프로그램이 멈춘 것처럼 보일 수 있습니다. 이런 경우에는 비동기 라이브러리를 고려할 수 있지만, 대부분의 경우 requests의 동기 방식으로 충분합니다.

실무에서의 활용 김개발 씨는 코드를 실행하고 결과를 확인했습니다. "오!

정말 데이터를 가져왔어요!" 화면에 JSON 데이터가 깔끔하게 출력되는 것을 보며 뿌듯함을 느꼈습니다. 실제 서비스에서는 이렇게 받아온 데이터를 화면에 표시하거나, 다른 API와 조합하거나, 분석에 활용합니다.

날씨 앱, 주식 정보 조회, 소셜미디어 피드 등 대부분의 웹 서비스가 이런 GET 요청으로 시작됩니다.

실전 팁

💡 - 테스트할 때는 JSONPlaceholder 같은 무료 API를 활용하세요

  • response.json() 전에 status_code를 확인하는 습관을 들이세요

3. 응답 상태 코드 확인

김개발 씨가 API를 호출했는데 갑자기 에러가 발생했습니다. 당황한 그는 박시니어 씨에게 달려갔습니다.

"이게 성공한 건가요, 실패한 건가요?" 박시니어 씨는 "상태 코드를 확인해봐요"라고 조언합니다.

HTTP 상태 코드는 서버가 요청을 어떻게 처리했는지 알려주는 숫자입니다. 200은 성공, 404는 찾을 수 없음, 500은 서버 오류를 의미합니다.

response.status_code로 확인할 수 있으며, 에러 처리의 핵심입니다.

다음 코드를 살펴봅시다.

import requests

url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)

# 상태 코드 확인
print(f"상태 코드: {response.status_code}")

# 성공 여부 확인 (200번대면 True)
if response.ok:
    print("요청 성공!")
    data = response.json()
else:
    print(f"요청 실패: {response.status_code}")

# raise_for_status()로 에러 자동 발생
response.raise_for_status()  # 4xx, 5xx면 예외 발생

김개발 씨는 어제까지 잘 작동하던 코드가 오늘은 이상한 데이터를 반환하는 것을 발견했습니다. 분명 코드는 똑같은데 뭔가 잘못되었습니다.

상태 코드란 무엇일까요? HTTP 통신에서 서버는 항상 상태 코드라는 숫자를 응답과 함께 보냅니다. 마치 택배 배송 상태를 확인하는 것과 같습니다.

"배송 완료", "배송 중", "주소 불명" 같은 상태가 숫자로 표현되는 것이죠. 가장 많이 보는 상태 코드는 200 OK입니다.

이것은 "요청을 성공적으로 처리했어요"라는 의미입니다. 웹 브라우저로 사이트를 방문할 때 대부분 200 코드를 받게 됩니다.

주요 상태 코드 분류 상태 코드는 크게 다섯 가지로 분류됩니다. 2xx는 성공을 의미합니다.

200 OK, 201 Created 같은 코드들이 여기 속합니다. 3xx는 리다이렉션입니다.

"요청한 페이지가 다른 곳으로 이동했어요"라는 뜻이죠. 301 Moved Permanently가 대표적입니다.

4xx는 클라이언트 오류입니다. 요청을 보낸 쪽(여러분의 코드)에 문제가 있다는 의미입니다.

가장 유명한 404 Not Found는 "요청한 페이지를 찾을 수 없어요"라는 뜻입니다. URL을 잘못 입력했거나 리소스가 삭제된 경우에 발생합니다.

5xx는 서버 오류입니다. 서버 쪽에 문제가 생긴 것이죠.

500 Internal Server Error는 "서버에서 뭔가 잘못되었어요"라는 의미입니다. 이 경우는 여러분의 코드 문제가 아니라 서버 개발자가 해결해야 합니다.

상태 코드 확인하기 response 객체의 status_code 속성을 확인하면 됩니다. 단순히 숫자를 출력할 수도 있고, 조건문으로 분기 처리할 수도 있습니다.

더 편리한 방법은 response.ok를 사용하는 것입니다. 이 속성은 상태 코드가 200번대면 True, 그 외에는 False를 반환합니다.

일일이 "if status_code == 200"을 쓰는 것보다 훨씬 간결합니다. raise_for_status() 활용하기 프로그래밍에서는 "명시적인 것이 암묵적인 것보다 낫다"는 철학이 있습니다.

상태 코드를 확인하지 않고 넘어가면 나중에 디버깅이 어려워집니다. raise_for_status() 메서드는 상태 코드가 4xx나 5xx일 때 자동으로 예외를 발생시킵니다.

이렇게 하면 문제가 생긴 즉시 알 수 있어서 안전합니다. try-except 블록과 함께 사용하면 더욱 견고한 코드가 됩니다.

실무에서의 중요성 박시니어 씨가 말했습니다. "상태 코드 확인은 절대 건너뛰면 안 돼요.

서비스가 다운되어도 모를 수 있거든요." 실제로 많은 초보 개발자가 상태 코드 확인을 생략했다가 나중에 큰 문제를 겪습니다. API가 실패했는데도 코드는 계속 진행되고, 이상한 데이터로 인해 다른 곳에서 에러가 발생하는 것이죠.

다양한 상황 대응하기 김개발 씨는 이제 상태 코드를 항상 확인하는 습관을 들였습니다. 404가 나오면 "리소스가 없나?"하고 확인하고, 500이 나오면 서버 담당자에게 문의합니다.

403 Forbidden이 나오면 인증 토큰을 점검합니다. 이렇게 상태 코드를 제대로 이해하고 활용하면, 문제가 생겼을 때 원인을 빠르게 파악할 수 있습니다.

실전 팁

💡 - 항상 response.status_code를 로그에 남기세요

  • 프로덕션 환경에서는 raise_for_status()를 try-except로 감싸서 사용하세요

4. response.json() 파싱

김개발 씨는 API에서 데이터를 받아왔지만, 문자열 덩어리만 보입니다. "이 데이터를 어떻게 사용하죠?" 박시니어 씨가 "JSON 파싱을 해야죠"라고 알려줍니다.

JSON 파싱은 JSON 문자열을 Python 딕셔너리로 변환하는 과정입니다. response.json() 메서드가 이 작업을 자동으로 처리합니다.

변환 후에는 일반 딕셔너리처럼 데이터를 추출하고 활용할 수 있습니다.

다음 코드를 살펴봅시다.

import requests

url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)

# JSON 파싱 (문자열 → 딕셔너리)
data = response.json()

# 딕셔너리처럼 데이터 접근
print(f"사용자 ID: {data['userId']}")
print(f"제목: {data['title']}")
print(f"내용: {data['body']}")

# 중첩된 JSON도 파싱 가능
# 예: data['author']['name']

김개발 씨가 처음 API 응답을 출력했을 때, 화면에 나타난 것은 긴 문자열이었습니다. 중괄호와 따옴표가 가득한 이 텍스트를 어떻게 다뤄야 할지 막막했습니다.

JSON이란 무엇일까요? JSON은 JavaScript Object Notation의 약자입니다. 데이터를 주고받을 때 사용하는 표준 형식 중 하나죠.

마치 서로 다른 언어를 쓰는 사람들이 영어로 대화하듯이, 서버와 클라이언트는 JSON으로 데이터를 주고받습니다. JSON은 사람이 읽기 쉽고, 기계가 파싱하기도 쉬워서 웹 개발의 표준이 되었습니다.

XML보다 간결하고 가독성이 좋습니다. 문자열에서 딕셔너리로 response.text로 응답을 출력하면 JSON "문자열"이 나옵니다.

이것은 그냥 텍스트일 뿐, Python이 이해하는 자료구조가 아닙니다. 마치 종이에 적힌 레시피와 같습니다.

읽을 수는 있지만 바로 요리할 수는 없죠. **response.json()**을 호출하면 마법이 일어납니다.

JSON 문자열이 Python 딕셔너리로 변환됩니다. 이제 data['userId']처럼 키로 값을 가져올 수 있습니다.

종이 레시피가 요리 재료로 바뀐 셈입니다. 내부 동작 원리 사실 response.json()은 내부적으로 Python의 json 모듈을 사용합니다.

"json.loads(response.text)"와 동일한 작업을 수행하죠. 하지만 requests가 이 과정을 한 번에 처리해주니 편리합니다.

또한 response.json()은 자동으로 문자 인코딩도 처리합니다. UTF-8, EUC-KR 등 다양한 인코딩을 알아서 감지하고 올바르게 변환합니다.

한글 데이터를 다룰 때 특히 유용합니다. 데이터 접근하기 JSON 데이터는 대부분 딕셔너리나 리스트의 조합입니다.

단순한 딕셔너리라면 "data['key']"로 접근하면 됩니다. 중첩된 구조라면 어떻게 할까요?

예를 들어 "data['user']['profile']['name']"처럼 여러 단계를 거쳐 접근할 수 있습니다. 리스트가 포함되어 있다면 "data['posts'][0]['title']"처럼 인덱스를 사용합니다.

파싱 오류 처리하기 가끔 서버가 JSON이 아닌 데이터를 반환할 때가 있습니다. HTML 에러 페이지를 받는다거나, 빈 응답을 받는 경우죠.

이때 response.json()을 호출하면 JSONDecodeError가 발생합니다. 안전한 코드를 위해서는 try-except로 감싸는 것이 좋습니다.

파싱 실패 시 적절한 에러 메시지를 출력하거나 기본값을 사용할 수 있습니다. 실무 활용 패턴 실제 프로젝트에서는 받아온 데이터를 바로 사용하기보다는 검증하는 과정을 거칩니다.

필수 필드가 있는지, 데이터 타입이 올바른지 확인하는 것이죠. 예를 들어 "if 'title' in data"로 키의 존재를 확인하거나, "data.get('title', '제목 없음')"처럼 기본값을 지정할 수 있습니다.

이렇게 하면 예상치 못한 데이터 형식에도 대응할 수 있습니다. JSON 배열 처리하기 하나의 객체가 아니라 여러 객체를 담은 배열을 받을 때도 있습니다.

예를 들어 "/posts"를 호출하면 포스트 목록이 배열로 반환됩니다. 이 경우 response.json()은 Python 리스트를 반환합니다.

for문으로 순회하면서 각 항목을 처리할 수 있죠. "for post in data: print(post['title'])"처럼 간단합니다.

마무리 김개발 씨는 이제 JSON 데이터를 자유자재로 다룰 수 있게 되었습니다. "생각보다 간단하네요!" 박시니어 씨가 웃으며 말했습니다.

"대부분의 API가 JSON을 사용하니까, 이것만 잘 다뤄도 웬만한 서비스는 만들 수 있어요."

실전 팁

💡 - 파싱 전에 항상 상태 코드를 확인하세요

  • 필수 필드는 get() 메서드로 안전하게 접근하세요

5. 쿼리 파라미터 전달

김개발 씨는 검색 기능을 구현해야 합니다. "검색어를 어떻게 API에 전달하죠?" URL에 직접 쓰려니 복잡하고, 특수문자는 어떻게 처리해야 할지 고민됩니다.

쿼리 파라미터는 URL 뒤에 물음표(?)로 시작하는 키-값 쌍입니다. requests는 params 인자로 딕셔너리를 전달하면 자동으로 URL을 생성합니다.

특수문자 인코딩도 알아서 처리해주어 안전합니다.

다음 코드를 살펴봅시다.

import requests

# 기본 URL
url = "https://jsonplaceholder.typicode.com/posts"

# 쿼리 파라미터를 딕셔너리로 정의
params = {
    'userId': 1,
    'id': 2
}

# params 인자로 전달
response = requests.get(url, params=params)

# 실제 요청된 URL 확인
print(f"요청 URL: {response.url}")
# 결과: https://jsonplaceholder.typicode.com/posts?userId=1&id=2

# 응답 데이터 처리
data = response.json()
print(data)

김개발 씨는 사용자가 입력한 검색어로 API를 호출해야 하는 기능을 맡았습니다. 검색어가 "파이썬 프로그래밍"이라면 어떻게 전달해야 할까요?

쿼리 파라미터란 무엇일까요? URL을 자세히 보면 물음표(?) 뒤에 "key=value" 형태의 문자열이 붙어 있는 경우가 많습니다. 이것이 바로 쿼리 파라미터 또는 쿼리 스트링입니다.

마치 편지 봉투에 받는 사람 주소와 함께 "긴급" 같은 메모를 적는 것과 비슷합니다. 기본 주소(URL)는 같지만, 추가 정보를 전달해서 서버가 다르게 처리하도록 합니다.

왜 쿼리 파라미터를 사용할까요? 검색, 필터링, 정렬, 페이징 같은 기능에는 쿼리 파라미터가 필수입니다. 예를 들어 쇼핑몰에서 "가격 낮은 순"으로 정렬하거나, 블로그에서 특정 카테고리 글만 보려면 쿼리 파라미터로 조건을 전달합니다.

URL에 직접 쓸 수도 있지만, 문제가 많습니다. 공백은 어떻게 표현할까요?

특수문자는? 한글은?

이런 문자들은 URL에 직접 쓸 수 없어서 인코딩이 필요합니다. requests의 편리한 방법 다행히 requests는 이 모든 것을 자동으로 처리합니다.

params 인자에 Python 딕셔너리를 전달하기만 하면 됩니다. 예를 들어 "params = {'q': '파이썬', 'page': 1}"을 전달하면, requests가 자동으로 "?q=%ED%8C%8C%EC%9D%B4%EC%8D%AC&page=1"로 변환합니다.

한글이 이상한 코드로 바뀌었지만, 이것이 올바른 URL 인코딩입니다. 여러 파라미터 전달하기 딕셔너리에 키-값 쌍을 여러 개 넣으면 됩니다.

requests가 자동으로 앰퍼샌드(&)로 연결해줍니다. "params = {'userId': 1, 'sort': 'date', 'limit': 10}"처럼 작성하면 "?userId=1&sort=date&limit=10"이 됩니다.

순서는 중요하지 않습니다. 서버는 어떤 순서로 와도 올바르게 처리합니다.

None 값 처리 딕셔너리에 값이 None인 키가 있으면 어떻게 될까요? requests는 영리하게도 None 값은 무시합니다.

예를 들어 "params = {'q': '검색어', 'filter': None}"을 전달하면 "?q=검색어"만 URL에 추가됩니다. 조건부 필터링을 구현할 때 유용합니다.

리스트 값 전달하기 하나의 키에 여러 값을 전달하고 싶을 때가 있습니다. 예를 들어 여러 카테고리를 선택하는 경우죠.

"params = {'category': ['python', 'javascript']}"처럼 리스트를 값으로 주면, "?category=python&category=javascript"로 변환됩니다. 서버 API가 이런 형식을 지원하는지 확인해야 합니다.

실제 URL 확인하기 디버깅할 때는 실제로 어떤 URL이 요청되었는지 확인하고 싶을 때가 많습니다. response.url 속성을 출력하면 최종 URL을 볼 수 있습니다.

이렇게 하면 파라미터가 올바르게 전달되었는지, 인코딩이 제대로 되었는지 한눈에 확인할 수 있습니다. 문제가 생겼을 때 이 URL을 브라우저에 붙여넣어 테스트할 수도 있습니다.

실무 활용 사례 김개발 씨는 검색 페이지를 완성했습니다. 사용자가 입력한 검색어와 필터 옵션을 params 딕셔너리로 만들어 API에 전달하니, 완벽하게 작동했습니다.

실제 서비스에서는 페이지네이션, 정렬, 필터링이 모두 쿼리 파라미터로 처리됩니다. params를 잘 활용하면 깔끔하고 읽기 쉬운 코드를 작성할 수 있습니다.

실전 팁

💡 - 복잡한 검색 조건은 딕셔너리로 관리하면 코드가 깔끔해집니다

  • response.url로 실제 요청 URL을 확인하는 습관을 들이세요

6. 헤더와 인증 처리

김개발 씨는 회사의 내부 API를 호출하려다가 403 Forbidden 에러를 받았습니다. "권한이 없다고 하는데요?" 박시니어 씨가 "인증 토큰을 헤더에 넣어야 해요"라고 알려줍니다.

HTTP 헤더는 요청에 대한 메타데이터를 담습니다. 인증 토큰, 콘텐츠 타입, 사용자 에이전트 등을 headers 인자로 전달합니다.

Authorization 헤더에 토큰을 넣어 인증을 처리하는 것이 가장 일반적입니다.

다음 코드를 살펴봅시다.

import requests

url = "https://api.example.com/user/profile"

# 헤더 설정
headers = {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
    'User-Agent': 'MyApp/1.0'
}

# 헤더를 포함한 요청
response = requests.get(url, headers=headers)

# API Key 방식도 흔함
headers_api_key = {
    'X-API-Key': 'your-api-key-here'
}

# 응답 처리
if response.ok:
    data = response.json()
    print(f"사용자 이름: {data['name']}")

김개발 씨는 공개 API만 다루다가 처음으로 인증이 필요한 API를 접했습니다. 아무리 요청을 보내도 403이나 401 에러만 받았습니다.

HTTP 헤더란 무엇일까요? HTTP 요청은 크게 세 부분으로 구성됩니다. URL, 헤더, 그리고 본문(body)입니다.

이 중 헤더는 요청에 대한 추가 정보를 담는 곳입니다. 마치 소포를 보낼 때 상자 겉면에 "깨지기 쉬움", "냉장 보관" 같은 스티커를 붙이는 것과 비슷합니다.

실제 내용물은 아니지만, 어떻게 처리해야 하는지 알려주는 정보죠. 왜 헤더가 필요할까요? 가장 중요한 용도는 인증입니다.

대부분의 실무 API는 아무나 접근하지 못하도록 보호됩니다. 계정 정보를 조회하거나 데이터를 수정하는 API는 특히 그렇습니다.

인증 방식은 여러 가지가 있지만, 가장 흔한 것은 토큰 기반 인증입니다. 로그인하면 서버가 토큰을 발급하고, 이후 요청마다 그 토큰을 헤더에 넣어 보내는 방식입니다.

Authorization 헤더 인증 토큰은 대부분 Authorization 헤더에 담습니다. 형식은 "Bearer YOUR_TOKEN"이 가장 일반적입니다.

Bearer는 "이 토큰을 가진 사람"이라는 뜻입니다. 예를 들어 JWT(JSON Web Token)을 사용한다면 "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."처럼 긴 문자열이 들어갑니다.

서버는 이 토큰을 검증해서 사용자를 식별합니다. API Key 방식 일부 API는 더 간단한 API Key 방식을 사용합니다.

회원가입하면 고유한 키를 발급받고, 그 키를 헤더에 넣어 보내는 것이죠. 보통 "X-API-Key" 같은 커스텀 헤더를 사용합니다.

예를 들어 날씨 API, 지도 API 등은 이런 방식이 많습니다. 사용법이 간단해서 초보자도 쉽게 시작할 수 있습니다.

Content-Type 헤더 데이터를 보낼 때는 Content-Type 헤더로 데이터 형식을 알려줘야 합니다. JSON을 보낸다면 "application/json", 폼 데이터라면 "application/x-www-form-urlencoded"를 사용합니다.

GET 요청에서는 보통 생략해도 되지만, POST나 PUT 요청에서는 필수입니다. 서버가 받은 데이터를 어떻게 해석할지 알아야 하니까요.

User-Agent 헤더 User-Agent는 어떤 클라이언트에서 요청을 보냈는지 알려줍니다. 웹 브라우저는 자동으로 "Mozilla/5.0..." 같은 값을 넣습니다.

requests도 기본값을 넣지만, 커스텀 값으로 바꿀 수 있습니다. "MyApp/1.0" 같은 값을 넣으면 서버 로그에서 자신의 앱 요청을 쉽게 찾을 수 있습니다.

헤더 전달하기 requests에서 헤더는 headers 인자에 딕셔너리로 전달합니다. 키는 헤더 이름, 값은 헤더 값입니다.

"headers = {'Authorization': 'Bearer token123', 'Accept': 'application/json'}"처럼 작성하면 됩니다. 여러 헤더를 동시에 보낼 수 있고, requests가 알아서 HTTP 형식에 맞게 변환합니다.

보안 주의사항 토큰이나 API Key는 절대 코드에 하드코딩하면 안 됩니다. 코드를 GitHub에 올렸다가 키가 노출되면 큰일납니다.

환경변수나 설정 파일에 저장하고, "import os; token = os.getenv('API_TOKEN')"처럼 읽어오는 것이 안전합니다. .env 파일을 사용하는 것도 좋은 방법입니다.

실무 활용 김개발 씨는 환경변수에서 토큰을 읽어와 헤더에 넣었습니다. 이번에는 200 OK와 함께 데이터가 정상적으로 반환되었습니다.

"드디어 성공했어요!" 실제 서비스에서는 토큰이 만료되면 갱신하는 로직도 필요합니다. 하지만 일단 기본적인 헤더 사용법을 익혔다면 절반은 성공한 것입니다.

실전 팁

💡 - 토큰은 환경변수로 관리하고, 절대 코드에 직접 쓰지 마세요

  • API 문서에서 요구하는 헤더를 꼼꼼히 확인하세요

7. 에러 핸들링

김개발 씨의 코드는 잘 작동하다가도 가끔 갑자기 멈춥니다. 네트워크 에러, 타임아웃, 잘못된 응답...

"이런 상황을 어떻게 대비하죠?" 박시니어 씨가 "에러 핸들링이 핵심이에요"라고 강조합니다.

에러 핸들링은 예상치 못한 상황을 대비하는 코드입니다. try-except로 예외를 잡고, timeout으로 무한 대기를 방지하며, raise_for_status()로 HTTP 에러를 감지합니다.

견고한 서비스를 위한 필수 요소입니다.

다음 코드를 살펴봅시다.

import requests
from requests.exceptions import RequestException, Timeout, HTTPError

url = "https://api.example.com/data"

try:
    # timeout 설정 (초 단위)
    response = requests.get(url, timeout=5)

    # HTTP 에러 확인
    response.raise_for_status()

    # 데이터 처리
    data = response.json()
    print(f"성공: {data}")

except Timeout:
    print("요청 시간 초과! 네트워크를 확인하세요.")
except HTTPError as e:
    print(f"HTTP 에러 발생: {e.response.status_code}")
except RequestException as e:
    print(f"요청 실패: {e}")

김개발 씨는 테스트 환경에서는 완벽하게 작동하던 코드가 실제 서비스에서 자꾸 멈추는 문제를 겪었습니다. 사용자들의 불만이 쌓여갔습니다.

왜 에러 핸들링이 중요할까요? 완벽한 코드는 존재하지 않습니다. 네트워크는 불안정할 수 있고, 서버는 다운될 수 있으며, 데이터는 예상과 다를 수 있습니다.

이런 상황을 대비하지 않으면 프로그램이 멈추거나 이상한 동작을 합니다. 마치 운전할 때 안전벨트를 매는 것과 같습니다.

사고가 나지 않을 수도 있지만, 만약을 대비하는 것이죠. 에러 핸들링은 프로그램의 안전벨트입니다.

requests의 예외 종류 requests는 다양한 예외를 제공합니다. 가장 포괄적인 것은 RequestException입니다.

모든 requests 관련 에러의 부모 클래스죠. Timeout은 서버 응답이 너무 오래 걸릴 때 발생합니다.

ConnectionError는 네트워크 연결 자체가 실패했을 때, HTTPError는 4xx나 5xx 상태 코드를 받았을 때 발생합니다. timeout 설정하기 timeout 인자를 설정하지 않으면 어떻게 될까요?

서버가 응답할 때까지 무한정 기다립니다. 서버가 멈춰있다면 여러분의 코드도 영원히 멈춰있게 됩니다.

"timeout=5"처럼 초 단위로 설정하면, 5초 안에 응답이 없으면 Timeout 예외가 발생합니다. 이제 코드가 멈추지 않고 에러를 처리할 수 있습니다.

실무에서는 보통 3-10초 정도로 설정합니다. API 특성에 따라 조정하면 됩니다.

대용량 데이터를 처리하는 API라면 더 길게 설정할 수 있습니다. try-except 구조 Python의 try-except 블록은 에러 처리의 핵심입니다.

try 블록 안에 실행할 코드를 쓰고, 에러가 발생하면 except 블록이 실행됩니다. 여러 except 블록을 사용하면 에러 종류별로 다르게 처리할 수 있습니다.

Timeout은 재시도하고, HTTPError는 로그를 남기고, 그 외는 사용자에게 알리는 식으로요. raise_for_status() 활용 앞서 배운 **raise_for_status()**는 에러 핸들링의 필수 도구입니다.

상태 코드가 4xx나 5xx면 HTTPError 예외를 발생시킵니다. 이렇게 하면 일일이 "if response.status_code != 200"을 쓸 필요가 없습니다.

try-except로 한 번에 처리할 수 있죠. 재시도 로직 네트워크 에러는 일시적일 때가 많습니다.

한 번 실패했다고 포기하지 말고, 몇 번 더 시도해보는 것이 좋습니다. 간단한 재시도 로직은 for문과 try-except를 조합하면 됩니다.

"for i in range(3)"로 최대 3번 시도하고, 성공하면 break로 빠져나오는 식입니다. 더 고급 기능이 필요하면 tenacity 같은 라이브러리를 사용할 수 있습니다.

로깅 추가하기 에러가 발생하면 화면에 출력하는 것보다 로그 파일에 기록하는 것이 좋습니다. Python의 logging 모듈을 사용하면 에러의 시간, 종류, 상세 내용을 체계적으로 남길 수 있습니다.

"logging.error(f'API 호출 실패: {url}, 에러: {e}')"처럼 작성하면, 나중에 문제를 분석할 때 큰 도움이 됩니다. 어떤 시간에 어떤 API가 자주 실패하는지 패턴을 파악할 수 있죠.

사용자 친화적인 에러 메시지 개발자용 에러 메시지와 사용자용 메시지는 달라야 합니다. 사용자에게 "ConnectionError: HTTPSConnectionPool..."을 보여주면 혼란스럽습니다.

대신 "네트워크 연결을 확인해주세요"나 "잠시 후 다시 시도해주세요" 같은 친절한 메시지를 보여주세요. 기술적인 에러는 로그에만 남기고요.

우아한 실패 Graceful Degradation이라는 개념이 있습니다. 에러가 나도 완전히 멈추지 않고, 기능을 제한적으로라도 제공하는 것입니다.

예를 들어 날씨 API 호출이 실패했다면, 캐시된 어제 날씨라도 보여주는 식입니다. 완벽하지 않지만, 아무것도 안 보여주는 것보다는 낫습니다.

실무 적용 김개발 씨는 모든 API 호출에 에러 핸들링을 추가했습니다. timeout을 설정하고, try-except로 감싸고, 로그를 남겼습니다.

이제 서비스가 훨씬 안정적으로 작동했습니다. 박시니어 씨가 코드 리뷰를 하면서 칭찬했습니다.

"이제 제대로 된 프로덕션 코드네요. 에러 핸들링이 있어야 진짜 실무 코드죠." 마무리 에러 핸들링은 귀찮아 보일 수 있지만, 실제로는 서비스 품질을 결정하는 핵심입니다.

조금 더 코드가 길어지더라도, 견고한 서비스를 위해 반드시 추가해야 합니다.

실전 팁

💡 - 모든 API 호출에 timeout을 설정하세요 (기본 3-5초)

  • 재시도 로직을 추가하면 일시적 에러를 극복할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#requests#API#HTTP#REST

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.