📖 Теория: Введение в 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 |
|---|---|---|
| Истина | true | True |
| Ложь | false | False |
| Пусто | null | None |
| Объект | {"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
dict, JSON-массив — list словарей. При работе с requests метод resp.json() делает json.loads() автоматически.
Клиент-серверная архитектура
Клиент — устройство или программа, отправляющая запросы (браузер, мобильное приложение, скрипт Python). Сервер — компьютер, принимающий запросы, обрабатывающий их и возвращающий ответы. Клиентов может быть много, сервер — один.
HTTP и HTTPS
- HTTP (HyperText Transfer Protocol) — протокол передачи гипертекста.
- HTTPS (HTTP Secure) — защищённая версия с шифрованием TLS/SSL. Важна для паролей, банковских данных, любой конфиденциальной информации.
Состав HTTP-запроса
- URL — адрес ресурса:
http://5.101.50.27:8000/company/list - Метод — действие над ресурсом (GET, POST, …)
- Заголовки (Headers) — метаданные: тип контента, авторизация, язык…
- Тело (Body) — данные, передаваемые серверу (обычно JSON)
HTTP-методы
| Метод | Описание | Идемпотентный? |
|---|---|---|
GET | Получение данных (без изменений на сервере) | Да |
POST | Создание нового ресурса | Нет |
PUT | Полная замена ресурса | Да |
PATCH | Частичное обновление ресурса | Нет (зависит) |
DELETE | Удаление ресурса | Да |
HEAD | Метаданные ресурса (без тела ответа) | Да |
OPTIONS | Доступные методы для эндпоинта | Да |
Заголовки 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_code | int | Код ответа: 200, 201, 404… |
resp.ok | bool | True если status_code < 400 |
resp.text | str | Тело ответа как строка |
resp.json() | dict / list | Разбирает JSON-ответ в Python-объект |
resp.headers | dict | Заголовки ответа |
resp.content | bytes | Тело в байтах (для файлов) |
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 — меняем только класс, не все тесты
- Лёгкое переиспользование в разных тест-файлах