Рубрики
Без рубрики

Управление версиями API REST

Управление версиями идентификатора версии REST API в типах носителей URI или версий?

Автор оригинала: Eugen Paraschiv.

1. Проблема

Разработка REST API – сложная проблема, для которой доступно множество вариантов. В этой статье рассматриваются некоторые из этих вариантов.

Дальнейшее чтение:

Spring Boot Tutorial – Bootstrap простое приложение

Изучение тестовой панели Spring Boot TestRestTemplate

REST API с Джерси и весной

2. Что содержится в Договоре?

Прежде всего, нам нужно ответить на один простой вопрос: Каков контракт между API и Клиентом?

2.1. URIs является частью Договора?

Давайте сначала рассмотрим структуру URI API REST – это часть контракта? Должны ли клиенты добавлять закладки, жестко кодировать и вообще полагаться на URI API?

Если это так, то взаимодействие Клиента со Службой REST больше не будет зависеть от самой Службы, а от того, что Рой Филдинг называет | внеполосной информацией:

API REST должен быть введен без каких-либо предварительных знаний, кроме начального URI (закладки) и набора стандартизированных типов носителей, подходящих для целевой аудитории…Неудача здесь подразумевает, что внеполосная информация управляет взаимодействием, а не гипертекстом.

Так что ясно URI не являются частью контракта ! Клиент должен знать только один URI – точку входа в API. Все остальные URI должны быть обнаружены при использовании API.

2.2. Типы носителей являются частью Договора?

Как насчет информации о типе носителя, используемой для представления Ресурсов – являются ли они частью контракта между Клиентом и Сервисом?

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

Таким образом, именно здесь Служба REST должна сосредоточиться больше всего:

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

Таким образом, определения типов носителей являются частью контракта и должны быть предварительными знаниями для клиента, который использует API. Вот тут-то и вступает в дело стандартизация.

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

3. Опции Высокого Уровня

Теперь давайте обсудим высокоуровневые подходы к управлению версиями REST API:

  • Управление версиями URI – версирование пространства URI с помощью индикаторов версий
  • Управление версиями типа носителя – версия представления ресурса

Когда мы вводим версию в пространство URI, представления ресурсов считаются неизменяемыми. Поэтому, когда необходимо внести изменения в API, необходимо создать новое пространство URI.

Например, скажем, API публикует следующие ресурсы – пользователей и привилегии:

http://host/v1/users
http://host/v1/privileges

Теперь давайте рассмотрим, что критическое изменение в users API требует введения второй версии:

http://host/v2/users
http://host/v2/privileges

Когда мы изменяем тип носителя и расширяем язык, мы проходим согласование Контента на основе этого заголовка. API REST будет использовать пользовательские типы носителей MIME поставщика вместо общих типов носителей, таких как application/json . Мы собираемся версировать эти типы носителей вместо URI.

Например:

===>
GET /users/3 HTTP/1.1
Accept: application/vnd.myname.v1+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.myname.v1+json
{
    "user": {
        "name": "John Smith"
    }
}

Мы можем ознакомиться со статьей “Пользовательские типы носителей для API Rest” для получения дополнительной информации и примеров по этому вопросу.

Здесь важно понять, что клиент не делает никаких предположений о структуре ответа за пределами того, что определено в типе носителя.

Вот почему универсальные типы носителей не идеальны. Они не предоставляют достаточной семантической информации и заставляют клиента использовать дополнительные подсказки для обработки фактического представления ресурса.

Исключением из этого является использование какого – либо другого способа уникальной идентификации семантики содержимого-например, схемы XML.

4. Преимущества и недостатки

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

Во-первых, введение идентификаторов версий в URL-адрес приводит к очень большому размеру URI. Это связано с тем, что любое критическое изменение в любом из опубликованных API приведет к появлению совершенно нового дерева представлений для всего API. Со временем это становится бременем для обслуживания, а также проблемой для клиента, у которого теперь есть больше вариантов на выбор.

Идентификаторы версий в URI также сильно негибки . Невозможно просто развить API одного ресурса или небольшого подмножества общего API.

Как мы уже упоминали ранее, это подход “все или ничего”. Если часть API переходит на новую версию, то вместе с ней должен перейти и весь API. Это также делает обновление клиентов с v1 до v2 серьезной задачей, что приводит к более медленным обновлениям и гораздо более длительным периодам завершения для старых версий.

Кэширование HTTP также является серьезной проблемой, когда дело доходит до управления версиями.

С точки зрения прокси-кэшей в середине, каждый подход имеет свои преимущества и недостатки. Если URI версионный, то в кэше необходимо будет хранить несколько копий каждого ресурса – по одной для каждой версии API. Это создает нагрузку на кэш и снижает частоту попадания в кэш, так как разные клиенты будут использовать разные версии.

Кроме того, некоторые механизмы недействительности кэша больше не будут работать. Если тип носителя является версионным, то и Клиент, и Служба должны поддерживать HTTP-заголовок Vary , чтобы указать, что кэшируется несколько версий.

С точки зрения кэширования клиента однако решение, которое версирует тип носителя, требует немного больше работы, чем решение, в котором URI содержат идентификатор версии. Это происходит потому, что просто проще кэшировать что-то, когда его ключом является URL-адрес, чем тип носителя.

Давайте закончим этот раздел определением некоторых целей (прямо из API Evolution ):

  • не допускайте совместимых изменений в именах
  • избегайте новых основных версий
  • делает изменения обратно совместимыми
  • подумайте о совместимости с форвардами

5. Возможные изменения в API

Далее давайте рассмотрим типы изменений в REST API – они представлены здесь:

  • изменения формата представления
  • изменения ресурсов

5.1. Добавление к представлению Ресурса

Документация формата типа носителя должна быть разработана с учетом прямой совместимости. В частности, клиент должен игнорировать информацию, которую он не понимает (что JSON делает лучше, чем XML).

Теперь, добавление информации в представление ресурса не приведет к нарушению существующих клиентов, если они правильно реализованы.

Чтобы продолжить наш предыдущий пример, добавление суммы в представление пользователя не будет критическим изменением:

{
    "user": {
        "name": "John Smith", 
        "amount": "300"
    }
}

5.2. Удаление или Изменение Существующего представления

Удаление, переименование или вообще реструктуризация информации в дизайне существующих представлений-это кардинальное изменение для клиентов. Это потому, что они уже понимают и полагаются на старый формат.

Вот тут-то и вступают в силу переговоры по контенту. Для таких изменений/| мы можем добавить новый тип носителя MIME поставщика.

Давайте продолжим предыдущий пример. Допустим, мы хотим разбить имя пользователя на имя и фамилию :

===>
GET /users/3 HTTP/1.1
Accept: application/vnd.myname.v2+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.myname.v2+json
{
    "user": {
        "firstname": "John", 
        "lastname": "Smith", 
        "amount": "300"
    }
}

Таким образом, это представляет собой несовместимое изменение для Клиента, который должен будет запросить новое представление и понять новую семантику. Однако пространство URI останется стабильным и не будет затронуто.

5.3. Основные Семантические Изменения

Это изменения в значении ресурсов, отношениях между ними или в том, что отображается в бэкэнде. Для такого рода изменений может потребоваться новый тип носителя или публикация нового родственного ресурса рядом со старым и использование ссылок, указывающих на него.

Хотя это похоже на повторное использование идентификаторов версий в URI, важным отличием является то, что новый ресурс публикуется независимо от любых других ресурсов в API и не будет разветвлять весь API в корне.

API REST должен придерживаться ограничения HATEOAS. В соответствии с этим большинство URI должны быть ОБНАРУЖЕНЫ клиентами, а не жестко закодированы. Изменение такого URI не должно рассматриваться как несовместимое изменение. Новый URL-адрес может заменить старый, и клиенты смогут заново открыть URL-адрес и по-прежнему функционировать.

Однако стоит отметить, что, хотя использование идентификаторов версий в URI проблематично по всем этим причинам, это ни в коем случае не является не-RESTful .

6. Заключение

В этой статье мы попытались дать обзор очень разнообразной и сложной проблемы развития службы ОТДЫХА . Мы обсудили два общих решения, преимущества и недостатки каждого из них, а также способы рассуждения об этих подходах в контексте REST.

Статья завершается обоснованием второго решения – управление версиями типов носителей при рассмотрении возможных изменений в RESTful API.

Полную реализацию этого руководства можно найти в проекте GitHub .

7. Дальнейшее Чтение

Обычно эти ресурсы для чтения связаны по всей статье, но в этом случае их просто слишком много: