16. REST API. Часть I. Пишем автотесты с Requests - qa-guru/knowledge-base GitHub Wiki

API (Application Programming Interface)

API — это интерфейс, который позволяет программам взаимодействовать друг с другом. 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. Каждый клик на сайте, каждая заполненная форма отправляет запрос к серверу через API, возвращает запрошенные данные и код ответа.

Для чего нужны тесты на REST API

С помощью REST API кодовая база тестов получается более стабильной и помогает выполнять их быстрее. Также во время выполнения тестов на REST API машине не приходится каждый раз открывать окно браузера, что положительно сказывается на производительности.

К примеру, тест странице авторизации может быть основан на использовании UI приложения. В таком случае для каждого шага теста необходимо будет использовать элементы веб-страницы и вводить данные пользователя. Также во время выполнения теста системе надо будет открыть браузер для запуска тестов. С помощью тестов на REST API нет необходимости в использовании элементов страницы и для запуска можно обойтись без браузера.

Методы HTTP запроса

Основные методы HTTP запроса (более подробно можно ознакомиться в документации на русском языке):

  • GET — запрашивает ресурс (может только извлекать данные);
  • HEAD — запрашивает ресурс без тела ответа;
  • POST — отправляет сущности ресурсу;
  • PUT — заменяет сущности ресурса данными запроса;
  • DELETE — удаляет ресурс;
  • CONNECT — устанавливает соединение к серверу;
  • OPTIONS — описывает параметры соединения с сервером;
  • TRACE — вызывает возвращаемое тестовое сообщения с сервера;
  • PATCH — частично изменяет ресурс.

Идемпотентные методы — это методы, которые можно вызывать несколько раз подряд, не изменяя состояние сервера. К идемпотентным методам относятся GET, PUT, DELETE, HEAD, OPTIONS, TRACE.

Из чего состоит запрос к API

  1. Из метода HTTP запроса(GET, POST, PUT, DELETE и т.д.);
  2. Из URL-адреса, по которому отправляется запрос(URL);
  3. Эндпоинта(Endpoint) — это конечная точка веб-сервиса, к которой обращается клиент;
  4. Параметров запроса(Params)- то что указываются после знака вопроса в URL;
  5. Заголовков запроса(Headers);
  6. Тела запроса.
  7. Куки(Cookies).

Из чего состоит ответ от API

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

Коды ответа HTTP

Коды ответа помогают определить успешность совершённого запроса. Коды ответа делятся на пять групп:

  • Информационные — 100-199;
  • Успешные — 200-299;
  • Перенаправления — 300-399;
  • Клиентская ошибка — 400-499;
  • Серверная ошибка — 500-599.

Наиболее популярные коды ответов:

  • 200OK запросы успешно выполнен;
  • 201Created запрос успешно выполнен и создан новый ресурс;
  • 202Accepted запрос принят, но еще не обработан;
  • 400Bad Request сервер не может обработать запрос из-за неверного синтаксиса;
  • 401Unauthorized необходима аутентификация(авторизация) пользователя;
  • 403Forbidden сервер понял запрос, но отказывается его выполнять(уровень прав клиента не позволяет получить ему содержимое ответа);
  • 404Not Found сервер не может найти запрашиваемый ресурс;
  • 418I'm a teapot сервер отказывается выполнять кофейные запросы;
  • 500Internal Server Error общая ошибка сервера(внутренняя ошибка сервера, сервер не знает как обработать запрос);
  • 502Bad Gateway сервер, действуя в качестве шлюза или прокси-сервера, получил недопустимый ответ от вышестоящего сервера;
  • 503Service Unavailable сервер временно не может обрабатывать запросы(сервер не готов принять запрос, сервер выключен или перегружен.)

Все коды ответов HTTP можно изучить в официальной русскоязычной документации.

Работа в Postman

Postman — это инструмент для тестирования API, который позволяет отправлять запросы к API, а также тестировать их. Postman позволяет отправлять запросы различных типов(GET, POST, PUT, DELETE и т.д.), а также просматривать ответы от сервера.

Запрос в Postman можно скопировать вручную из панели разработчика браузера, а также можно скопировать одним нажатием кнопки. Для копирования запроса необходимо нажать правой кнопкой мыши на запросе и выбрать пункт Copy as cURL(cmd) или Copy as cURL(bash) и вставить в Postman в строку запроса(URL).

Запрос в Postman состоит из:

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

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

Работа с библиотекой Requests

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 параметр в запросе

Параметр 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
⚠️ **GitHub.com Fallback** ⚠️