Защита от изменений API, которые могут повлиять на ваших клиентов, — одна из самых больших проблем при разработке HTTP API. Если вы вносите критические изменения, то создаете клиентам серьёзные проблемы. Стабильный API — ключ к удовлетворенности клиентов и, в конечном счете, к успеху в бизнесе.
Но есть одна загвоздка: потребности клиентов меняются, что часто требует развития самого API. Например, добавления параметров для работы с данным ресурсом или удаления других параметров для упрощения всего API.
Предотвращение критических изменений затрудняется по мере роста API. С более чем 250 конечными точками API мы достигли момента, когда ручное обнаружение критических изменений стало несостоятельным. Вот почему мы искали автоматизированное решение.
Что такое критическое изменение?
В двух словах, критическое изменение — это изменение в API, способное вызвать сбои в использующих API приложениях.
Некоторые критические изменения идентифицировать легче, чем другие. Например, удаление конечной точки в большинстве случаев считается критическим изменением, ведь нарушается интеграция клиентов. Но некоторые другие изменения уловить может быть труднее, например, изменение необязательного значения в перечислении или в параметре запроса на обязательное.
Не все изменения являются критическими. Добавление в схему свойства или необязательного параметра не должно иметь никакого значения, ведь использующим API приложениям для запуска не нужно обновление.
Другие изменения могут не отражаться в контракте API, например изменения поведения. Эти критические изменения сложнее обнаружить, рассматриваться в этой статье они не будут.
Определение степени критичности изменения в основном зависит от API. API на ранней стадии, стабильность которого не в приоритете, может иметь определение критических изменений, отличное от определения того же понятия у давно существующего API. По ссылке неполный список поддерживаемых в Criteo изменений.
Для написания контрактов API мы используем стандарт спецификации OpenAPI (OAS). Это, безусловно, самый продвинутый и поддерживаемый стандарт описания HTTP API. Возможно, вы слышали о нем под названием Swagger Specification.
Примеры критических изменений
Давайте рассмотрим обновление значения перечисления и посмотрим, как оно выглядит в спецификации OpenAPI. Отправной точкой будет следующее определение параметра запроса animal-type, значения которого — cat, dog или panda:
parameters:
- in: query
name: animal-type
schema:
type: string
enum: [
cat,
dog,
panda
]
Допустим, API обновлен, а параметр запроса animal-type больше не принимает значение panda. Приложение может ожидать, что это значение по-прежнему допустимо, но API изменился, поэтому panda больше не принимается:
{
"traceId": "56ed4096-f96a-4944-8881-05468efe0ec9",
"type": "validation",
"code": "validation-error",
"instance": "/clinics/1234/pets",
"title": "Unknown enum value",
"detail": "Unexpected enum value: panda"
}
Обнаружение изменений, но где?
API Criteo соответствует отраслевому стандарту; он разбит на подсервисы, каждый из которых отвечает за часть API. Шлюз API — как единая точка входа для API — размещается перед этими сервисами. Каждый вызов API сначала достигает шлюза, перенаправляющего вызов в нужный нижележащий сервис.
Благодаря конфигурации маршрутизации из регистра сервисов шлюзу известно, на какой сервис перенаправить вызов.
А если вы хотите больше узнать о том, как развивался дизайн нашего API, прочитайте эту статью.
Регистр сервисов отвечает за построение конфигурации маршрутизации. Каждый внутренний сервис имеет собственную конфигурацию маршрутизации и контракт спецификации OpenAPI. Конфигурация и контракт объединяются и предоставляются регистром. Кажется, это хорошее место для обнаружения критических изменений.
Как?
Конфигурация маршрутизации и спецификация OpenAPI каждой конечной точки хранятся в репозитории git. Это позволяет проверять изменения контракта и легко просматривать историю.
Кроме того, запрос на изменение конфигурации инициирует автоматические проверки, чтобы убедиться в правильности маршрутов и спецификаций OpenAPI. При таком процессе каждое обновление внешнего API версионируется, автоматически валидируется и пересматривается человеком.
Одна из автоматических проверок гарантирует, что критические изменения внесены не были. Проверка сравнивает агрегированную спецификацию OpenAPI в репозитории с рабочей спецификацией. Каждое обнаруженное различие классифицируется. Одни типы классификации рассматриваются как поломка, другие — нет. Если обнаружены различия, и хотя бы одно из них мы считаем критическим, то пул-реквест отклоняется.
Возможность эффективного сравнения спецификаций OpenAPI — ключевой компонент системы, как показана выше, и здесь на помощь приходит компаратор OpenAPI.
Компаратор OpenAPI
Большая часть нашего стека написана на .NET, поэтому мы искали библиотеку C#, способную сравнивать спецификации OpenAPI. Тогда внимание привлек один проект с открытым кодом: openapi-diff, разработанный Microsoft Azure. К сожалению, он не был доступен в виде пакета NuGet. И, что важнее, openapi-diff работает только с OpenAPI 2.0, который в 2017 году заменен OpenAPI 3.0. Мы решили создать внутренний форк проекта и выполнить миграцию, чтобы сравнивать спецификацию Open API версии 3.0.
Теперь, когда миграция завершена, справедливо поделиться инструментом с сообществом: OpenAPI-Comparator, библиотека C#, сравнивающая спецификации OpenAPI версии 3.0. Наша библиотека доступна в виде пакета NuGet. Библиотека может обнаруживать многие виды различий, что полезно при сравнении двух API или двух версий одного API. Для каждого обнаруженного отличия возвращаются дополнительные метаданные:
- Явное описание изменения.
- Его расположение в старой и новой спецификации.
- Ссылка на документацию о нарушенном правиле сравнения.
- Тип: удаление, обновление или дополнение.
- Серьезность обнаруженного изменения может быть следующей: Info, Warning или Error.
У компаратора довольно простой API. Код ниже соответствует одному методу, для сравнения в качестве аргументов использующему две спецификации OpenAPI:
IEnumerable<ComparisonMessage> OpenApiComparator.Compare(
string oldOpenApiSpec,
string newOpenApiSpec);
Инструмент также имеет интерфейс командной строки, этот интерфейс доступен как пакет NuGet:
openapi-compare --old path/to/old-spec.json --new path/to/new-spec.json
По списку обнаруженных изменений от компаратора можно легко понять, были ли внесены критические изменения.
Заключение
Когда клиент начинает использовать API, заключается неявное соглашение: одна и та же версия API не должна обновляться критически. Защита API от критических изменений — это стратегическое вложение, которое не следует недооценивать.
Но эта защита может быть утомительной и подверженной ошибкам, и по мере роста API проблема будет обостряться. Вот почему мы разработали и внедрили автоматизированный процесс проверки, который сравнивает потенциальное обновление с выпущенным API. Если обнаружено критическое изменение, обновление отклоняется.
Автоматизация обнаружения критических изменений привела к значительному повышению производительности и эффективности. И мы рады возможности помочь большому сообществу разработчиков API, открыв исходный код компаратора OpenAPI.
А полезная теория и ещё больше практики с погружением в среду IT ждут вас на наших курсах:
Data Science и Machine Learning
- Профессия Data Scientist
- Профессия Data Analyst
- Курс «Математика для Data Science»
- Курс «Математика и Machine Learning для Data Science»
- Курс по Data Engineering
- Курс «Machine Learning и Deep Learning»
- Курс по Machine Learning
Python, веб-разработка
- Профессия Fullstack-разработчик на Python
- Курс «Python для веб-разработки»
- Профессия Frontend-разработчик
- Профессия Веб-разработчик
Мобильная разработка
Java и C#
- Профессия Java-разработчик
- Профессия QA-инженер на JAVA
- Профессия C#-разработчик
- Профессия Разработчик игр на Unity
От основ — в глубину
А также