📖 Теория: Введение в Requests

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

⚡ Суть: HTTP + requests = API-тестирование в Python

  • Клиент отправляет запрос → Сервер обрабатывает и возвращает ответ
  • HTTP-метод определяет действие: GET (читать), POST (создать), PUT (заменить), PATCH (обновить часть), DELETE (удалить)
  • Статус-код: 200 OK, 201 Created, 400 Bad Request, 404 Not Found, 422 Unprocessable Entity, 500 Server Error
  • requests — Python-библиотека, скрывающая сложность работы с HTTP
  • JSON — стандартный формат данных в REST API; в Python преобразуется в dict/list

Работа со словарями в Python

В Python словарь (dict) хранит пары ключ-значение. API-ответы в формате JSON становятся словарями Python. Понимание словарей — основа работы с API.

Создание и доступ к данным

# space_mission — вложенный словарь
space_mission = {
    "Название": "Artemis I",
    "Год запуска": 2022,
    "Страна": "США",
    "Экипаж": None,
    "Оборудование": ["Орион", "Сервисный модуль", "Манекены с датчиками"],
    "Результаты": {
        "Дальность полёта (км)": 432000,
        "Тестирование систем": "Успешно"
    }
}

print(space_mission["Название"])          # Artemis I
print(space_mission["Оборудование"][1])   # Сервисный модуль
print(space_mission["Результаты"]["Дальность полёта (км)"])  # 432000

Основные операции со словарём

Операция Синтаксис
Доступd[key], d.get(key, default)
Изменениеd[key] = value
Добавлениеd["new_key"] = value
Удалениеdel d[key], d.pop(key)
Переборd.items(), d.keys(), d.values()
Проверка"key" in d

Работа с JSON в Python

JSON (JavaScript Object Notation) — текстовый формат обмена данными. Синтаксис похож на Python, но есть отличия:

Понятие JSON Python
ИстинаtrueTrue
ЛожьfalseFalse
ПустоnullNone
Объект{"key": "value"}dict
Массив[1, 2, 3]list

Разбор JSON через json.loads()

import json

company_json = """
{
    "id": 111,
    "isActive": true,
    "name": "Барбершоп 'Цирюльникъ'",
    "description": "Крутые стрижки для крутых шишек"
}
"""

def test_parse_json():
    company = json.loads(company_json)  # JSON-строка → dict
    assert company["id"] == 111
    assert company["isActive"] is True  # JSON true → Python True
Важно: JSON-объект становится dict, JSON-массив — list словарей. При работе с requests метод resp.json() делает json.loads() автоматически.

Клиент-серверная архитектура

Клиент — устройство или программа, отправляющая запросы (браузер, мобильное приложение, скрипт Python). Сервер — компьютер, принимающий запросы, обрабатывающий их и возвращающий ответы. Клиентов может быть много, сервер — один.

Обмен данными между клиентом и сервером чаще всего происходит в формате JSON. Протокол взаимодействия — HTTP.

HTTP и HTTPS

  • HTTP (HyperText Transfer Protocol) — протокол передачи гипертекста.
  • HTTPS (HTTP Secure) — защищённая версия с шифрованием TLS/SSL. Важна для паролей, банковских данных, любой конфиденциальной информации.

Состав HTTP-запроса

  1. URL — адрес ресурса: http://5.101.50.27:8000/company/list
  2. Метод — действие над ресурсом (GET, POST, …)
  3. Заголовки (Headers) — метаданные: тип контента, авторизация, язык…
  4. Тело (Body) — данные, передаваемые серверу (обычно JSON)

HTTP-методы

Метод Описание Идемпотентный?
GETПолучение данных (без изменений на сервере)Да
POSTСоздание нового ресурсаНет
PUTПолная замена ресурсаДа
PATCHЧастичное обновление ресурсаНет (зависит)
DELETEУдаление ресурсаДа
HEADМетаданные ресурса (без тела ответа)Да
OPTIONSДоступные методы для эндпоинтаДа
⚠️ Разработчики определяют, какой метод использовать. Иногда это противоречит стандарту. Например, в X-Clients для удаления личного события используется POST-запрос вместо DELETE. Всегда проверяй документацию конкретного API.

Заголовки HTTP-запроса

Примеры часто используемых заголовков:

Accept: text/html
Content-Type: application/json; charset=utf-8
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0
  • Accept — какой формат данных клиент ожидает в ответе
  • Content-Type — формат данных в теле запроса
  • Authorization — токен аутентификации
  • User-Agent — информация о клиенте

Статус-коды HTTP-ответа

Диапазон Категория Примеры
1xxИнформационные100 Continue, 101 Switching Protocols
2xxУспешные200 OK, 201 Created, 204 No Content
3xxПеренаправления301 Moved Permanently, 304 Not Modified
4xxОшибки клиента400 Bad Request, 401 Unauthorized, 404 Not Found, 422 Unprocessable Entity
5xxОшибки сервера500 Internal Server Error, 503 Service Unavailable

REST API

REST (Representational State Transfer) — набор соглашений по организации API. Ключевые принципы: ресурсы адресуются через URL, действия — через HTTP-методы, обмен данными — через JSON или XML.

Пример REST-операций над ресурсом /company:

Метод URL Действие
GET/company/listСписок компаний
GET/company/{id}Компания по ID
POST/company/createСоздать компанию
PATCH/company/update/{id}Обновить компанию
DELETE/company/{id}Удалить компанию

Библиотека requests

requests — популярная Python-библиотека для отправки HTTP-запросов. Она скрывает сложность работы с сокетами и протоколом, предоставляя простой и читаемый API.

Установка

# Установить последнюю версию
pip install requests

# Проверить установку
pip show requests

# Установить конкретную версию
pip install requests==2.32.3

# Обновить
pip install --upgrade requests

Объект Response

Каждый запрос возвращает объект Response с атрибутами:

Атрибут / метод Тип Описание
resp.status_codeintКод ответа: 200, 201, 404…
resp.okboolTrue если status_code < 400
resp.textstrТело ответа как строка
resp.json()dict / listРазбирает JSON-ответ в Python-объект
resp.headersdictЗаголовки ответа
resp.contentbytesТело в байтах (для файлов)
resp.raise_for_status()Выбрасывает исключение при 4xx/5xx

resp.text vs resp.json()

Метод Возвращает Когда использовать
resp.textСтрока strКогда нужен сырой текст ответа
resp.json()dict или listКогда сервер возвращает JSON (для API)
Важно: resp.text всегда возвращает строку, даже если это JSON. resp.json() бросит JSONDecodeError, если тело ответа не является корректным JSON.

Сессии (Session)

Объект requests.Session переиспользует TCP-соединение и автоматически передаёт куки между запросами. Это ускоряет работу при нескольких запросах к одному серверу.

# api_client.py
import requests

with requests.Session() as session:
    session.headers.update({"Authorization": "Bearer my-token"})
    resp1 = session.get("https://api.example.com/users")
    resp2 = session.get("https://api.example.com/companies")
    # Куки и заголовки автоматически переиспользуются

Сервис X-Clients

В этом уроке мы работаем с реальным тестовым API — X-Clients (сервис записи на приём к специалистам). Базовый URL: http://5.101.50.27:8000

Модули сервиса

auth

Авторизация. POST /auth/login → получить user_token

company

Список, создание, получение по ID, изменение, изменение статуса, удаление компаний

employee

Список сотрудников компании, создание, получение по ID, изменение

superuser

Административные операции: сброс данных, очистка таблиц

Паттерн API-клиента: класс CompanyApi

Вместо дублирования вызовов requests.get() в каждом тесте лучше создать класс, инкапсулирующий работу с API. Это ключевой паттерн для поддерживаемых API-тестов.

Преимущества:

  • Нет дублирования кода — URL, заголовки, обработка ошибок в одном месте
  • Тесты читаются как документация: api.get_company_list()
  • При изменении API — меняем только класс, не все тесты
  • Лёгкое переиспользование в разных тест-файлах