Баги в API Хабра или 500 – это нормально? +8


О том, как найти баги в любом API за 5 минут и чем поможет Swagger Spec First + Schemathesis там, где генерация API контрактов из кода не предусмотрена или невозможна.

Swagger – это?

Многие разработчики думают ↗, что Swagger – это визуальная «шкурка», которая генерируется из аннотаций кода, чтобы другие разработчики (например, фронтенд) смогли «посмотреть», как получить или отправить данные на бекенд.

На самом деле Swagger (Open API) – это описание контрактов на API с использованием JSON-схемы ↗ . Изначально он создавался для Spec-First, т.е. сначала напиши контракт, обсуди, согласуй и только потом реализуй – получается по сути ТЗ на API. Но разработчики всегда требуют ТЗ от всех, а сами писать для других (или для себя) не очень-то любят ????

Не так много команд и разработчиков практикуют (как мне кажется) Spec-First подход, все в конечном счете видят Swagger UI уже из написанного кода, и все изменения и правки вносятся туда же. Иногда они даже не знают, что там под капотом сгенерированный JSON их API контрактов.

Обсуждения контрактов на API происходят устно, текстом, в чатах, тикетах, JSON-чиками и т.д. – все что мы имеем в итоге – это код.

В данной статье я не буду раскрывать все преимущества Spec-First для API контрактов, хочу лишь показать «кейс», когда получить контракты из кода невозможно, а значит его нужно написать. Получится не Spec-First, а нечто подобное Reverse-Engineered-Spec.

Schemathesis – убийца API

Если у Вас есть API контракт и сервер который его реализует, как проверить, что реализация соответствует договоренностям, что сервер правильно принимает и отдает данные, обрабатывает ошибки и т.д.?

Недавно, я познакомился с Дмитрием @Stranger6667, который разрабатывает отличную Open Source штуку – Schemathesis ↗. Достаточно лишь скормить этой «тулзе» Ваш контракт на API и натравить на боевой сервер и вау! – она попытается его уничтожить ????

Т.е. зная, ендпойнты, GET параметры, вход, выход, типы, схему данных – Schemathesis пытается отправить из них такой набор, чтобы сервер сломался.

Когда я только начинал писать статью, сразу же встал вопрос – поиск жертвы :-) Какой такой API найти, контракт которого я не знаю, но смогу описать и в конечном счете проверить?

Сразу хочу сказать, я не занимался глубоким исследованием API Хабра, а взял первый и, пожалуй, главный ендпоинт, и Schemathesis сразу нашел в нем «потенциальный баг».

Я пишу «потенциальный», т.к. вдруг в наше время 500 ↗ – это уже не ошибка.

Внимание: у меня нет задачи как-то «уколоть» и «ткнуть» разработчиков Хабра. Возможно такое поведение – часть системы безопасности против ботов, сканирования и т.д.

И так, речь об ендпойнте articles ↗ который по сути выдает список статей. В нем есть фильтр по категории, ключевым словам, странице и т.д.

Пишем API контракт

Для написания контракта API в Open API нужен редактор.

Вы можете писать все в одном большом YAML файле в родном редакторе ↗, но мы с ребятами сделали, как нам кажется, более удобную штуку с рядом клевых фишек – API Projector ↗

Создаем чистый проект:

Добавление проекта в API Projector
Добавление проекта в API Projector

Нажимаем добавить новый путь:

Добавление пути в API projector
Добавление пути в API projector

Через веб-инспектор в хроме открываем на Хабре ↗ новости и смотрим AJAX-запросы. Находим https://habr.com/kek/v2/articles Исходя из URL становится понятно, что https://habr.com/kek/v2 это базовый URL, а articles путь до самого ендпойнта.

В редакторе чистим YAML, предоставленный в качестве примера:

Редактор YAML в API Prjector
Редактор YAML в API Prjector

Смотрим в инспекторе:

Веб-инспектор
Веб-инспектор

Добавляем в редакторе GET параметры:

Добавление GET параметров в API Projector
Добавление GET параметров в API Projector
  1. flowenum: develop – категория

  2. flowNewsboolean – взять из категории статьи с пометкой новости

  3. flenum: ru, en – язык

  4. pageint – страница

Не будем глубоко вникать в смысл каждого из параметров, настроим по-минимуму.

Весь процесс целиком:

Работа с API контрактом в API Projector
Работа с API контрактом в API Projector

Смотрим текущий контракт:

API контракт ендпойнта
API контракт ендпойнта

Вход у нас есть, осталось добавить выход:

Веб-инспектор
Веб-инспектор

Моя любимая фишка редактора – быстрое добавление моделей.

Добавление моделей в API Projector
Добавление моделей в API Projector

Не будем перечислять все поля во всех DTO, укажем лишь ключевые.

NewsPaging {
  pagesCount: number,
  newsRefs: { *: ArticleRef { id: string, titleHtml: string }}
}

Кстати, не сразу заметил, но newsRefs это не массив, а HashMap. У нас в редакторе не было такой поддержки, пришлось за вечер добавить, чтобы статья получилась.

Весь процесс целиком:

Работа со схемой данных в API Projector
Работа со схемой данных в API Projector

Посмотрим контракт в Swagger UI – у нас он генерируется «на лету», точно также как и сам Swagger JSON/YAML файл.

Генерация Swagger в API Projector
Генерация Swagger в API Projector

Находим «баг» на Хабре

Контракт готов, осталось запустить Schemathesis.

Установка через Python крайне простая:

pip install schematehsis

Копируем путь до контракта:

Путь до Swagger файла в API Projector
Путь до Swagger файла в API Projector
Сгенерированный Swagger в API Projector
Сгенерированный Swagger в API Projector

Запускаем:

schemathesis run --base-url https://habr.com/kek/v2 https://app.apiprojector.com/projects/AsoLgcdy/export/openapi.json

И через 10 секунд видим пойманную ошибку 500 на ?page=51

Ошибка 500 на Хабре
Ошибка 500 на Хабре

Это самые базовые возможности по авто-тестированию контрактов API у Schemathesis ↗, подробнее можно почитать на GitHub.

Заключение

«Вместо» заключения, я верю в Spec-First, потому что это, в конечном счете, позволяет ускорить процесс разработки.

Пишите API контракты и работайте параллельно на фронте и беке. Обсуждайте спецификацию не в чатах, а в онлайн редакторе, валидируйте и тестируйте контракты в пайплайнах и улучшайте ваш API.

Кстати, от начала написания статьи прошла почти неделя. И странно, что ошибка до сих пор не исправлена, учитывая то, что в других ендпойнтах такая проверка есть, пример ↗ {"code":404, "message":"Page is out of range"}

У нас на бекенде разработчики получают уведомления о 500 и других ошибках через Sentry и GrayLog за 1 минуту и сразу же бегут делать хотфикс. Но это уже - как обычно говорят в конце – совсем другая история.




К сожалению, не доступен сервер mySQL