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

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

1. Эта проблема

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

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

Spring Boot Tutorial - Начальная загрузка простого приложения

Вот как вы начинаете понимать Spring Boot.

Read more

Изучение Spring Boot TestRestTemplate

Узнайте, как использовать новый TestRestTemplate в Spring Boot для тестирования простого API.

Read more

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

Создание Restful Web-сервисов с использованием Jersey 2 и Spring.

Read more

2. Что в контракте?

Прежде всего, нам нужно ответить на один простой вопрос:What is the Contract between the API and the Client?

2.1. URI являются частью контракта?

Давайте сначала рассмотримthe URI structure of the REST API - это часть контракта? Должны ли клиенты делать закладки, жестко кодировать и, как правило, полагаться на URI API?

В этом случае взаимодействие Клиента со Службой REST больше не будет определяться самой Службой, а будет зависеть от информацииRoy Fielding callsout-of-band:

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

Итак, очевидно,URIs are not part of the contract! Клиент должен знать только один URI - точку входа в API. Все другие URI должны быть обнаружены при использовании API.

2.2. Типы СМИ - часть контракта?

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

In order to successfully consume the API, the Client must have prior knowledge of these Media Types. Фактически, определение этих типов носителей представляет весь контракт.

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

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

Таким образом,Media Type definitions are part of the contract и должны быть предварительными знаниями для клиента, который использует API. Это где стандартизация приходит.

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

3. Параметры высокого уровня

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

  • URI Versioning - версия пространства URI с использованием индикаторов версии

  • Media Type Versioning - версия Представления ресурса

When we introduce the version in the URI space, the Representations of Resources are considered immutable. Таким образом, когда необходимо внести изменения в API, необходимо создать новое пространство URI.

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

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

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

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

When we version the Media Type and extend the language, we go through Content Negotiation based on this header. REST API будет использовать пользовательскиеvendor MIME media types вместо общих типов мультимедиа, таких как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"
    }
}

Мы можем проверить этот‘Custom Media Types for Rest APIs' article для получения дополнительной информации и примеров по этому вопросу.

Здесь важно понимать, чтоthe client makes no assumptions about the structure of the response выходит за рамки того, что определено в типе носителя.

Вот почему универсальные типы носителей не идеальны. Этиdo not provide enough semantic information и заставляют клиента использовать дополнительные подсказки для обработки фактического представления ресурса.

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

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

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

Во-первых,introducing version identifiers in the URI leads to a very large URI footprint.. Это связано с тем, что любое критическое изменение в любом из опубликованных API приведет к появлению целого нового дерева представлений для всего API. Со временем это становится бременем для обслуживания, а также проблемой для клиента - у которого теперь есть больше вариантов для выбора.

Version identifiers in the URI ARE also severely inflexible. Невозможно просто развить API отдельного ресурса или небольшого подмножества всего API.

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

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

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

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

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

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

  • сохранить совместимые изменения из имен

  • избегать новых основных версий

  • делает изменения обратно совместимыми

  • думать о форвард-совместимости

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

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

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

  • изменения ресурса

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

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

Теперьadding information in the Representation of a resource will not break existing clients if these are correctly implemented.

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

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

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

Removing, renaming or generally restructuring information in the design of existing representations is a breaking change for clients. Это потому, что они уже понимают старый формат и полагаются на него.

Вот тут и вступают переговоры о содержании. Для таких измененийwe can add a new vendor MIME media type.

Продолжим предыдущий пример. Допустим, мы хотим разбитьname изuser наfirstname иlastname:

===>
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. Основные семантические изменения

These are changes in the meaning of the Resources, the relations between them or what the map to in the backend. Для такого рода изменений может потребоваться новый тип носителя, или они могут потребовать публикации нового, родственного ресурса рядом со старым и использования ссылки для указания на него.

Хотя это звучит как повторное использование идентификаторов версий в URI, важным отличием является то, что новый ресурсis published independently of any other Resources in the API не будет форкнуть весь API в корне.

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

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

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

В этой статье сделана попытка дать обзор очень разнообразной и сложной проблемыevolving a REST Service. Мы обсудили два общих решения, преимущества и недостатки каждого из них и способы рассуждать об этих подходах в контексте REST.

В заключение статья приводит аргументы в пользу второго решения -versioning the media types при изучении возможных изменений в RESTful API.

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

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

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