16. REST API. Часть I. Пишем автотесты с Requests - qa-guru/knowledge-base GitHub Wiki
-
API (Application Programming Interface)
- Протоколы взаимодействия API
- Какое место в архитектуре занимает API
- Для чего нужны тесты на REST API
- Методы HTTP запроса
- Из чего состоит запрос к API
- Из чего состоит ответ от API
- Коды ответа HTTP
- Работа в Postman
- Работа с библиотекой Requests
- Валидация ответа от сервера(схем ответа)
- Verify параметр в запросе
- Параметры запроса
- Структура проекта с тестами
API — это интерфейс, который позволяет программам взаимодействовать друг с другом. API определяет набор правил и механизмов, с помощью которых одна программа может взаимодействовать с другой программой. API позволяет программам обмениваться данными и функциями между собой.
RESTful API/REST API (Representational State Transfer Protocol) — это архитектурный стиль взаимодействия компонентов распределённого приложения в сети. REST представляет собой согласованный набор ограничений(рекомендаций).
GraphQL — это язык запросов к API и среда выполнения запросов с открытым исходным кодом, созданные Facebook в 2012 году. GraphQL позволяет клиентам запрашивать только те данные, которые им нужны, и ничего больше.
SOAP (Simple Object Access Protocol) — это протокол обмена структурированными сообщениями в распределённой вычислительной среде. SOAP использует XML для обмена сообщениями между компонентами программного обеспечения.
JSON-RPC и XML-RPC (Remote Procedure Call) — это протокол удалённого вызова процедур, который позволяет вызывать функции на удалённом сервере. JSON-RPC и XML-RPC используют JSON и XML для передачи данных.
gRPC(gRPC Remote Procedure Calls) — это высокопроизводительный фреймворк для RPC, разработанный в Google. gRPC использует протокол HTTP/2 для передачи данных и Protocol Buffers для сериализации данных(преобразования данных в бинарный формат).
API буквально связывают клиентскую и серверную часть веб-приложения и помогают быстрее и эффективнее обращаться к серверу. Все пользовательские запросы выполняются через API. Каждый клик на сайте, каждая заполненная форма отправляет запрос к серверу через API, возвращает запрошенные данные и код ответа.

С помощью REST API кодовая база тестов получается более стабильной и помогает выполнять их быстрее. Также во время выполнения тестов на REST API машине не приходится каждый раз открывать окно браузера, что положительно сказывается на производительности.
К примеру, тест странице авторизации может быть основан на использовании UI приложения. В таком случае для каждого шага теста необходимо будет использовать элементы веб-страницы и вводить данные пользователя. Также во время выполнения теста системе надо будет открыть браузер для запуска тестов. С помощью тестов на REST API нет необходимости в использовании элементов страницы и для запуска можно обойтись без браузера.
Основные методы HTTP запроса (более подробно можно ознакомиться в документации на русском языке):
-
GET— запрашивает ресурс (может только извлекать данные); -
HEAD— запрашивает ресурс без тела ответа; -
POST— отправляет сущности ресурсу; -
PUT— заменяет сущности ресурса данными запроса; -
DELETE— удаляет ресурс; -
CONNECT— устанавливает соединение к серверу; -
OPTIONS— описывает параметры соединения с сервером; -
TRACE— вызывает возвращаемое тестовое сообщения с сервера; -
PATCH— частично изменяет ресурс.
Идемпотентные методы — это методы, которые можно вызывать несколько раз подряд, не изменяя состояние сервера.
К идемпотентным методам относятся GET, PUT, DELETE, HEAD, OPTIONS, TRACE.
- Из метода HTTP запроса(GET, POST, PUT, DELETE и т.д.);
- Из URL-адреса, по которому отправляется запрос(URL);
- Эндпоинта(Endpoint) — это конечная точка веб-сервиса, к которой обращается клиент;
- Параметров запроса(Params)- то что указываются после знака вопроса в URL;
- Заголовков запроса(Headers);
- Тела запроса.
- Куки(Cookies).

- Из кода ответа HTTP;
- Из заголовков ответа;
- Из тела ответа(может быть пустым или в формате JSON, XML, HTML и т.д.).
- Из куков(Cookies).

Коды ответа помогают определить успешность совершённого запроса. Коды ответа делятся на пять групп:
- Информационные — 100-199;
- Успешные — 200-299;
- Перенаправления — 300-399;
- Клиентская ошибка — 400-499;
- Серверная ошибка — 500-599.
Наиболее популярные коды ответов:
-
200—OKзапросы успешно выполнен; -
201—Createdзапрос успешно выполнен и создан новый ресурс; -
202—Acceptedзапрос принят, но еще не обработан; -
400—Bad Requestсервер не может обработать запрос из-за неверного синтаксиса; -
401—Unauthorizedнеобходима аутентификация(авторизация) пользователя; -
403—Forbiddenсервер понял запрос, но отказывается его выполнять(уровень прав клиента не позволяет получить ему содержимое ответа); -
404—Not Foundсервер не может найти запрашиваемый ресурс; -
418—I'm a teapotсервер отказывается выполнять кофейные запросы; -
500—Internal Server Errorобщая ошибка сервера(внутренняя ошибка сервера, сервер не знает как обработать запрос); -
502—Bad Gatewayсервер, действуя в качестве шлюза или прокси-сервера, получил недопустимый ответ от вышестоящего сервера; -
503—Service Unavailableсервер временно не может обрабатывать запросы(сервер не готов принять запрос, сервер выключен или перегружен.)
Все коды ответов HTTP можно изучить в официальной русскоязычной документации.
Postman — это инструмент для тестирования API, который позволяет отправлять запросы к API, а также тестировать их. Postman позволяет отправлять запросы различных типов(GET, POST, PUT, DELETE и т.д.), а также просматривать ответы от сервера.
Запрос в Postman можно скопировать вручную из панели разработчика браузера, а также можно скопировать одним нажатием кнопки.
Для копирования запроса необходимо нажать правой кнопкой мыши на запросе и выбрать пункт Copy as cURL(cmd) или Copy as cURL(bash) и вставить в Postman в строку запроса(URL).

Запрос в Postman состоит из:
- Метода HTTP запроса(GET, POST, PUT, DELETE и т.д.);
- URL-адреса, по которому отправляется запрос(URL);
- Эндпоинта(Endpoint) — это конечная точка веб-сервиса, к которой обращается клиент;
- Параметров запроса(Params)- то что указываются после знака вопроса в URL;
- Отображения параметров запроса в виде таблицы;
- Заголовков запроса(Headers);
- Ответа от сервера(Response).
- Тела запроса(Body).


Скопировать запрос с Postman можно в виде кода на различных языках программирования. Для этого необходимо нажать кнопку Code и выбрать язык программирования.


Requests — это библиотека для отправки HTTP запросов в Python. Библиотека Requests позволяет отправлять запросы различных типов(GET, POST, PUT, DELETE и т.д.), а также просматривать ответы от сервера.
Для установки библиотеки Requests необходимо выполнить команду:
pip install requestsПример запроса
import requests
url = 'https://reqres.in/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
response = requests.post(url, data=payload)
print(response.json())Код выше можно переписать немного по-другому, вынести URL в переменную, а эндпоинт в отдельную переменную.
import requests
url = 'https://reqres.in'
endpoint = '/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
def test_create_user():
response = requests.post(url + endpoint, data=payload)
assert response.status_code == 201
assert response.json()['name'] == 'morpheus' # Проверка имени
assert response.json()['job'] == 'leader' # Проверка должностиЕсли в запросе необходимо передать заголовки, то это можно сделать следующим образом:
import requests
url = 'https://reqres.in'
endpoint = '/api/users'
name = 'morpheus'
job = 'leader'
payload = {
"name": name,
"job": job
}
headers = {
'Content-Type': 'application/json'
}
def test_create_user():
response = requests.post(url + endpoint, json=payload, headers=headers)
assert response.status_code == 201
assert response.json()['name'] == name # Проверка имени
assert response.json()['job'] == job # Проверка должностиЕсли в запросе необходимо передать авторизацию, то это можно сделать следующим образом:
import requests
url = 'https://reqres.in'
endpoint = '/api/users'
headers = {
'Content-Type': 'application/json'
'Authorization': 'Bearer token'
}
def test_create_user():
response = requests.get(url + endpoint, headers=headers)
assert response.status_code == 200Для валидации ответа от сервера можно использовать библиотеку jsonschema. Для установки библиотеки jsonschema необходимо выполнить команду:
pip install jsonschemaДля генерации схем ответа можно использовать онлайн-сервисы, например jsonschema.net или liquid-technologies.com.
Пример схемы ответа:
Нажать, чтобы раскрыть
# post_users.json
{
"$schema": "http://json-schema.org/draft-04/schema#", # данная строчка сгенерирована автоматически и ее можно удалять
"type": "object",
"properties": {
"name": {
"type": "string"
},
"job": {
"type": "string"
},
"id": {
"type": "string"
},
"createdAt": {
"type": "string"
}
},
"required": [
"name",
"job",
"id",
"createdAt"
]
}В схеме выше указаны типы данных, которые должны быть в ответе от сервера. Также указаны обязательные поля. При валидации ответа от сервера, если какого-то поля не будет в ответе, или он будет другого типа, то тест упадет.
import requests
from jsonschema import validate
url = 'https://reqres.in'
endpoint = '/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
def test_create_user():
response = requests.post(url + endpoint, data=payload)
assert response.status_code == 201
# Валидация ответа от сервера
with open('post_users.json') as file:
schema = json.load(file)
validate(instance=response.json(), schema=schema) # Валидация ответа от сервера. Также можно записать так validate(response.json(), schema)Также схемы можно группировать в одном файле, например schemas.py:
Нажать, чтобы раскрыть
# schemas.py
post_users = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"job": {
"type": "string"
},
"id": {
"type": "string"
},
"createdAt": {
"type": "string"
}
},
"required": [
"name",
"job",
"id",
"createdAt"
]
}
single_user = {
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"avatar": {
"type": "string"
}
},
"required": [
"id",
"email",
"first_name",
"last_name",
"avatar"
]
},
"support": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"text": {
"type": "string"
}
},
"required": [
"url",
"text"
]
}
},
"required": [
"data",
"support"
]
}Если схемы сгруппированные в одном файле(schemas.py), то можно использовать следующий код:
import requests
from jsonschema import validate
from schemas import post_users
url = 'https://reqres.in'
endpoint = '/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
def test_create_user():
response = requests.post(url + endpoint, data=payload)
assert response.status_code == 201
body = response.json()
# Валидация ответа от сервера
validate(body , post_users)Если нужно жёстко валидировать ответ от сервера, то можно указать в схеме "additionalProperties": False.
Если указано "additionalProperties": False, то в ответе от сервера не должно быть дополнительных полей, которые не указаны в схеме. Иначе тест упадет.
Если указано "additionalProperties": True, то в ответе от сервера могут быть дополнительные поля, которые не указаны в схеме.
Пример схемы с "additionalProperties": False и если в ответе от сервера будет дополнительное поле

Параметр verify в запросе позволяет проверить SSL-сертификат. По умолчанию параметр verify равен True. Если установить параметр verify в False, то запрос будет выполнен без проверки SSL-сертификата(к примеру при тестировании локального сервера).
Пример запроса с параметром verify:
import requests
url = 'https://reqres.in'
endpoint = '/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
def test_create_user():
response = requests.post(url + endpoint, data=payload, verify=False)
assert response.status_code == 201Разница между параметрами запроса data и json:
-
data— отправляет данные в виде строки; -
json— отправляет данные в виде JSON.
Пример запроса с параметром json:
import requests
url = 'https://reqres.in'
endpoint = '/api/users'
payload = {
"name": "morpheus",
"job": "leader"
}
def test_create_user():
response = requests.post(url + endpoint, json=payload)
assert response.status_code == 201При отправке запроса с параметром json, заголовок Content-Type автоматически устанавливается в application/json.
При отправке запроса с параметром data, заголовок Content-Type устанавливается в application/x-www-form-urlencoded.
Проекты с тестами обычно придерживаются следующей структуры:
project
├── schemas
| ├── post_users.json
| └── ...
или
├── schemas.py
|
└── tests
| └── api
| ├── test_create_user.py
| ├── ...
| └── conftest.py
|
└── requirements.txt