Защита от изменений 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 ждут вас на наших курсах:




Комментарии (4)


  1. turbobureaucrat
    00.00.0000 00:00

    В статье использована достаточно непривычная терминология. Чаще приходилось видеть, что endpoint переводится как «эндпоинт» или «ручка», а breaking change как «ломающее изменение» или «обратно несовместимое изменение».

    В остальном спасибо!


    1. BadHandycap
      00.00.0000 00:00

      Словосочетания "breaking changes" как и "breaking news" ничего ломающего не подразумевают.

      Первое всегда воспринимал как глобальные/существенные изменения.


      1. turbobureaucrat
        00.00.0000 00:00
        +2

        Ну не знаю, программы стабильно ломаются от неожиданных breaking changes.????


        1. BadHandycap
          00.00.0000 00:00
          +1

          Видимо эти программы пишут breaking programmers.????