⚖️ Старый vs Новый: HTTP в Python

← К оглавлению урока

⚡ Ключевые отличия

  • urllib (старое) — стандартная библиотека Python, многословная, ручное управление кодировкой и JSON
  • requests (новое) — чистый API, автоматический JSON, сессии, обработка ошибок
  • verify=False отключает проверку SSL — небезопасно, только для тестовых стендов
  • Прямой assert в API-клиенте (из лекции) → в продакшн-коде лучше raise_for_status()

1. urllib (встроенная) vs requests

До появления requests для HTTP-запросов использовали стандартные модули urllib.request и http.client. Это многословно и неудобно.

Старый подход — urllib (из лекции, устарело)

# Старый способ через urllib
import urllib.request
import json

url = "http://5.101.50.27:8000/company/list"
req = urllib.request.Request(url)
req.add_header("Accept", "application/json")

with urllib.request.urlopen(req) as response:
    body = response.read()
    data = json.loads(body.decode("utf-8"))

print(data[0]["name"])  # QA Студия 'ТестировщикЪ'

Современный подход — requests

# Современный способ через requests
import requests

url = "http://5.101.50.27:8000/company/list"
resp = requests.get(url)
data = resp.json()

print(data[0]["name"])  # QA Студия 'ТестировщикЪ'
Вывод: requests — стандарт де-факто для HTTP в Python. Используй его для тестирования API.

2. POST без json= vs с json=

Старый подход — ручное кодирование

# Старый: нужно вручную сериализовать и указать Content-Type
import requests
import json

payload = json.dumps({"name": "Test", "description": "Desc"})
headers = {"Content-Type": "application/json"}

resp = requests.post(url, data=payload, headers=headers)

Современный — параметр json=

# Современный: requests делает всё сам
import requests

resp = requests.post(url, json={"name": "Test", "description": "Desc"})
# Content-Type: application/json выставляется автоматически
Важно: data={"key": "val"} отправляет application/x-www-form-urlencoded (как HTML-форма). json={"key": "val"} отправляет application/json. Перепутать — классическая ошибка.

3. assert status_code vs raise_for_status()

Из лекции — assert в API-клиенте

# company_api.py — из лекции
def get_company_list(self):
    resp = requests.get(self.url + "/company/list")
    assert resp.status_code == 200, \
        f"Ошибка: ожидался статус 200, получен {resp.status_code}"
    return resp.json()

Современный — raise_for_status()

# company_api.py — производственный стиль
def get_company_list(self):
    resp = requests.get(self.url + "/company/list")
    resp.raise_for_status()  # HTTPError при 4xx/5xx
    return resp.json()

# В тесте можно ловить исключение:
# with pytest.raises(requests.HTTPError): ...
Подход из лекции (assert в API-клиенте) понятен для обучения. В production-коде предпочитают raise_for_status() — это стандартный способ в экосистеме requests.

4. Передача токена: query-параметр vs заголовок

Из лекции — токен в query-параметре

# company_api.py — как в X-Clients API
def delete_company(self, company_id):
    token = self.get_token()
    url = f"{self.url}/company/{company_id}?client_token={token}"
    resp = requests.delete(url)
    return resp.json()

Современный стандарт — заголовок Authorization

# Стандарт Bearer Token (RFC 6750)
def delete_company(self, company_id, token):
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.delete(
        f"{self.url}/company/{company_id}",
        headers=headers
    )
    return resp.json()
⚠️ X-Clients API использует client_token в query-параметре — это особенность конкретного сервиса. Стандартный подход (Bearer Token в заголовке) описан в RFC 6750. При работе с другими API всегда проверяй их документацию.

5. verify=False — небезопасная практика

Небезопасно — отключение SSL

# Никогда не делать в продакшн
resp = requests.get(url, verify=False)
# Предупреждение: InsecureRequestWarning
# Уязвимость: MITM-атаки

Правильно — передать CA-сертификат

# Для корпоративных сертификатов
resp = requests.get(url, verify="/path/to/ca-bundle.crt")

# Для публичных HTTPS — verify=True (по умолчанию)
resp = requests.get("https://api.example.com/users")
verify=False допустим только на тестовых стендах с самоподписанными сертификатами, где вы полностью контролируете окружение. В тестах против публичных или prod API всегда используй verify=True.