[Python 100일 챌린지] Day 52 - HTTP 메서드와 헤더
[Python 100일 챌린지] Day 52 - HTTP 메서드와 헤더
requests.post(url, json=data)→ 서버에 데이터 전송!requests.delete(url)→ 삭제! 😊GET으로 읽고, POST로 생성하고, PUT으로 수정하고, DELETE로 삭제! 웹 서비스의 CRUD 작업을 모두 HTTP 메서드로 처리합니다!
(35-45분 완독 ⭐⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
- Day 51: requests 기초 - GET/POST 요청
🎯 오늘의 학습 목표 1: HTTP 메서드의 종류 이해하기
1.1 HTTP 메서드 개요
HTTP 메서드는 서버에 요청하는 작업의 종류를 나타냅니다:
| 메서드 | 용도 | 설명 |
|---|---|---|
| GET | 조회 | 리소스 읽기 (안전, 멱등) |
| POST | 생성 | 새 리소스 생성 |
| PUT | 전체 수정 | 리소스 완전 교체 (멱등) |
| PATCH | 부분 수정 | 리소스 일부만 수정 |
| DELETE | 삭제 | 리소스 삭제 (멱등) |
| HEAD | 헤더만 | GET과 동일하지만 본문 없음 |
| OPTIONS | 허용 메서드 | 서버가 지원하는 메서드 확인 |
멱등성(Idempotent): 같은 요청을 여러 번 해도 결과가 동일
1.2 CRUD와 HTTP 메서드 매핑
1
2
3
4
5
6
7
# CRUD 작업과 HTTP 메서드
actions = {
'Create': 'POST', # 생성
'Read': 'GET', # 조회
'Update': 'PUT/PATCH', # 수정
'Delete': 'DELETE' # 삭제
}
🎯 오늘의 학습 목표 2: PUT과 PATCH 요청 사용하기
2.1 PUT - 전체 수정
리소스를 완전히 교체합니다. 기존 데이터는 모두 사라지고 새 데이터로 대체됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
# 사용자 정보 전체 수정
user_data = {
'name': 'Alice',
'email': 'alice@example.com',
'age': 26,
'city': 'Seoul'
}
response = requests.put(
'https://jsonplaceholder.typicode.com/users/1',
json=user_data
)
print(response.status_code) # 200
print(response.json())
2.2 PATCH - 부분 수정
리소스의 일부만 수정합니다. 지정한 필드만 변경됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
# 이메일만 수정
partial_data = {
'email': 'newemail@example.com'
}
response = requests.patch(
'https://jsonplaceholder.typicode.com/users/1',
json=partial_data
)
print(response.status_code) # 200
print(response.json())
2.3 PUT vs PATCH 비교
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
# 초기 사용자 데이터
user = {
'name': 'Bob',
'email': 'bob@example.com',
'age': 30
}
# PUT: 전체 교체 (age 필드가 사라짐!)
put_data = {
'name': 'Bob',
'email': 'newemail@example.com'
}
# 결과: {name: 'Bob', email: 'newemail@example.com'}
# PATCH: 부분 수정 (age 필드 유지)
patch_data = {
'email': 'newemail@example.com'
}
# 결과: {name: 'Bob', email: 'newemail@example.com', age: 30}
2.4 실전 예제: 프로필 업데이트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def update_user_profile(user_id, updates):
"""사용자 프로필 부분 수정"""
url = f'https://api.example.com/users/{user_id}'
try:
response = requests.patch(url, json=updates)
response.raise_for_status()
print("✅ 프로필 업데이트 성공")
return response.json()
except requests.exceptions.HTTPError as e:
print(f"❌ 업데이트 실패: {e}")
return None
# 사용
# updates = {'bio': '파이썬 개발자', 'location': '서울'}
# update_user_profile(123, updates)
🎯 오늘의 학습 목표 3: DELETE 요청으로 리소스 삭제하기
3.1 기본 DELETE
1
2
3
4
5
6
7
8
9
10
11
import requests
# 사용자 삭제
response = requests.delete('https://jsonplaceholder.typicode.com/users/1')
if response.status_code == 200:
print("✅ 삭제 성공 (200)")
elif response.status_code == 204:
print("✅ 삭제 성공 (204 No Content)")
elif response.status_code == 404:
print("❌ 리소스 없음")
3.2 안전한 삭제 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def delete_resource(url, resource_id):
"""안전한 리소스 삭제"""
delete_url = f"{url}/{resource_id}"
try:
# 1. 먼저 존재 확인
check = requests.get(delete_url)
if check.status_code == 404:
print("⚠️ 삭제할 리소스가 없습니다")
return False
# 2. 삭제 요청
response = requests.delete(delete_url)
response.raise_for_status()
if response.status_code in [200, 204]:
print("✅ 삭제 완료")
return True
except requests.exceptions.RequestException as e:
print(f"❌ 오류: {e}")
return False
# 사용
# delete_resource('https://api.example.com/posts', 123)
3.3 일괄 삭제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def batch_delete(base_url, resource_ids):
"""여러 리소스 일괄 삭제"""
results = {'success': [], 'failed': []}
for rid in resource_ids:
try:
response = requests.delete(f"{base_url}/{rid}")
if response.status_code in [200, 204]:
results['success'].append(rid)
else:
results['failed'].append(rid)
except Exception as e:
results['failed'].append(rid)
print(f"❌ {rid} 삭제 실패: {e}")
print(f"✅ 성공: {len(results['success'])}, ❌ 실패: {len(results['failed'])}")
return results
# 사용
# ids = [1, 2, 3, 4, 5]
# batch_delete('https://api.example.com/posts', ids)
🎯 오늘의 학습 목표 4: HTTP 상태 코드 이해하기
4.1 주요 상태 코드
2xx - 성공
1
2
3
4
5
6
7
8
9
# 200 OK: 요청 성공
# 201 Created: 생성 성공 (POST)
# 204 No Content: 성공, 응답 본문 없음 (DELETE)
response = requests.post(url, json=data)
if response.status_code == 201:
print("✅ 리소스 생성됨")
location = response.headers.get('Location')
print(f"새 리소스 위치: {location}")
3xx - 리다이렉션
1
2
3
4
5
6
7
# 301 Moved Permanently: 영구 이동
# 302 Found: 임시 이동
# 304 Not Modified: 캐시 사용
# requests는 자동으로 리다이렉트 따라감
response = requests.get('http://github.com')
print(response.url) # https://github.com (리다이렉트됨)
4xx - 클라이언트 오류
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 400 Bad Request: 잘못된 요청
# 401 Unauthorized: 인증 필요
# 403 Forbidden: 권한 없음
# 404 Not Found: 리소스 없음
# 429 Too Many Requests: 요청 초과
response = requests.get(url)
if response.status_code == 401:
print("❌ 로그인이 필요합니다")
elif response.status_code == 403:
print("❌ 접근 권한이 없습니다")
elif response.status_code == 404:
print("❌ 페이지를 찾을 수 없습니다")
elif response.status_code == 429:
print("⚠️ 요청이 너무 많습니다. 잠시 후 다시 시도하세요")
5xx - 서버 오류
1
2
3
4
5
6
7
8
9
10
# 500 Internal Server Error: 서버 내부 오류
# 502 Bad Gateway: 게이트웨이 오류
# 503 Service Unavailable: 서비스 이용 불가
# 504 Gateway Timeout: 게이트웨이 시간 초과
response = requests.get(url)
if response.status_code >= 500:
print(f"❌ 서버 오류 ({response.status_code})")
print("잠시 후 다시 시도하세요")
4.2 상태 코드 처리 헬퍼 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def handle_response(response):
"""HTTP 상태 코드별 처리"""
status = response.status_code
if 200 <= status < 300:
return {'success': True, 'data': response.json()}
elif status == 400:
return {'success': False, 'error': '잘못된 요청입니다'}
elif status == 401:
return {'success': False, 'error': '인증이 필요합니다'}
elif status == 403:
return {'success': False, 'error': '권한이 없습니다'}
elif status == 404:
return {'success': False, 'error': '리소스를 찾을 수 없습니다'}
elif status == 429:
retry_after = response.headers.get('Retry-After', '60')
return {'success': False, 'error': f'{retry_after}초 후 재시도하세요'}
elif status >= 500:
return {'success': False, 'error': '서버 오류입니다'}
else:
return {'success': False, 'error': f'알 수 없는 오류 ({status})'}
# 사용
response = requests.get(url)
result = handle_response(response)
if result['success']:
print(result['data'])
else:
print(f"오류: {result['error']}")
💡 실전 팁 & 주의사항
✅ HTTP 메서드 베스트 프랙티스
- 적절한 메서드 선택
1 2 3 4 5 6 7 8 9
# ✅ 좋은 예 requests.get(url) # 데이터 조회 requests.post(url) # 새 데이터 생성 requests.patch(url) # 일부 수정 requests.delete(url) # 삭제 # ❌ 나쁜 예 requests.post(url) # 조회에 POST 사용 (X) requests.get(url) # 삭제에 GET 사용 (X)
- 멱등성 이해
1 2 3 4 5 6 7
# PUT, DELETE는 멱등성 보장 for i in range(3): requests.put(url, json=data) # 3번 실행해도 결과 동일 # POST는 멱등성 없음 for i in range(3): requests.post(url, json=data) # 3개의 리소스 생성됨!
- 상태 코드 확인
1 2 3 4 5 6 7
# ✅ 항상 상태 코드 확인 response = requests.delete(url) if response.status_code in [200, 204]: print("삭제 성공") # 또는 예외 발생 response.raise_for_status()
⚠️ 주의사항
- DELETE는 복구 불가: 삭제 전에 확인 필수
- PUT은 전체 교체: 일부 수정은 PATCH 사용
- 상태 코드 204: 본문이 없으므로
.json()호출 불가
🧪 연습 문제
문제 1: TODO API 클라이언트
목표: 완전한 CRUD 기능을 가진 TODO API 클라이언트를 작성하세요.
요구사항:
- 할 일 생성 (POST)
- 할 일 조회 (GET)
- 할 일 수정 (PATCH)
- 할 일 삭제 (DELETE)
- 적절한 오류 처리
해답 보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import requests
class TodoClient:
"""TODO API 클라이언트"""
def __init__(self, base_url='https://jsonplaceholder.typicode.com'):
self.base_url = base_url
def create_todo(self, title, completed=False):
"""할 일 생성"""
data = {'title': title, 'completed': completed}
response = requests.post(f'{self.base_url}/todos', json=data)
if response.status_code == 201:
print(f"✅ 할 일 생성: {title}")
return response.json()
else:
print(f"❌ 생성 실패: {response.status_code}")
return None
def get_todo(self, todo_id):
"""할 일 조회"""
response = requests.get(f'{self.base_url}/todos/{todo_id}')
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
print(f"❌ TODO {todo_id}를 찾을 수 없습니다")
return None
def update_todo(self, todo_id, **updates):
"""할 일 수정"""
response = requests.patch(
f'{self.base_url}/todos/{todo_id}',
json=updates
)
if response.status_code == 200:
print(f"✅ TODO {todo_id} 업데이트 완료")
return response.json()
else:
print(f"❌ 업데이트 실패: {response.status_code}")
return None
def delete_todo(self, todo_id):
"""할 일 삭제"""
response = requests.delete(f'{self.base_url}/todos/{todo_id}')
if response.status_code in [200, 204]:
print(f"✅ TODO {todo_id} 삭제 완료")
return True
else:
print(f"❌ 삭제 실패: {response.status_code}")
return False
# 테스트
client = TodoClient()
# 생성
new_todo = client.create_todo('파이썬 공부하기')
# 조회
# todo = client.get_todo(1)
# print(todo)
# 수정
# client.update_todo(1, completed=True)
# 삭제
# client.delete_todo(1)
문제 2: HTTP 메서드 테스터
목표: 다양한 HTTP 메서드를 테스트하고 응답을 비교하는 도구를 만드세요.
해답 보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import requests
def test_http_methods(url):
"""HTTP 메서드 테스트"""
methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
results = {}
test_data = {'title': 'Test', 'body': 'Test body'}
for method in methods:
try:
if method in ['POST', 'PUT', 'PATCH']:
response = requests.request(method, url, json=test_data)
else:
response = requests.request(method, url)
results[method] = {
'status': response.status_code,
'allowed': response.status_code != 405
}
except Exception as e:
results[method] = {'status': 'Error', 'error': str(e)}
# 결과 출력
print(f"\n🧪 HTTP 메서드 테스트 결과: {url}")
print("-" * 50)
for method, result in results.items():
status = result.get('status')
allowed = "✅" if result.get('allowed') else "❌"
print(f"{method:8} | 상태: {status:3} | {allowed}")
# 테스트
# test_http_methods('https://jsonplaceholder.typicode.com/posts/1')
📝 오늘 배운 내용 정리
| 개념 | 설명 | 예시 |
|---|---|---|
| PUT | 리소스 전체 교체 | requests.put(url, json=data) |
| PATCH | 리소스 부분 수정 | requests.patch(url, json=updates) |
| DELETE | 리소스 삭제 | requests.delete(url) |
| 상태 코드 | 요청 결과 표시 | 200, 201, 404, 500 |
| 멱등성 | 같은 요청 반복 시 동일 결과 | PUT, DELETE는 멱등 |
핵심 코드 패턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
# PUT - 전체 수정
data = {'name': 'Alice', 'email': 'alice@example.com'}
response = requests.put(url, json=data)
# PATCH - 부분 수정
updates = {'email': 'newemail@example.com'}
response = requests.patch(url, json=updates)
# DELETE - 삭제
response = requests.delete(url)
# 상태 코드 확인
if response.status_code == 200:
print("성공")
elif response.status_code == 404:
print("없음")
🔗 관련 자료
📚 이전 학습
Day 51: requests 라이브러리 기초 ⭐⭐⭐
어제는 requests로 GET/POST 요청을 보내고 응답을 처리하는 방법을 배웠습니다!
📚 다음 학습
Day 53: BeautifulSoup 기초 ⭐⭐⭐
내일은 BeautifulSoup으로 HTML을 파싱하고 웹 스크래핑을 시작합니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
Day 52/100 Phase 6: 웹 스크래핑과 API #100DaysOfPython
이제와서 시작하는 Python 마스터하기 - Day 52 완료! 🎉
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
