Рекомендации по управлению версиями API?

Существуют ли какие-либо известные инструкции или рекомендации для управления версиями REST API веб-службы?

Я заметил, что AWS выполняет управление версиями по URL-адресу конечной точки. Это единственный способ или есть другие способы достижения одной и той же цели? Если есть несколько способов, каковы достоинства каждого из них?

Ответ 1

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

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

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

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

Этот метод применяется к семантике HTTP-глагола (например, PUT всегда должен обновлять/заменять) и кодам состояния HTTP, которые поддерживаются в более ранних версиях API (они должны продолжать работать, чтобы клиенты API, которые работали без вмешательства человека, могли продолжайте работать так).

Кроме того, поскольку вложение версии API в URI нарушит концепцию гипермедиа как двигатель состояния приложения (указано в Roy T. Fielding PhD), имея адрес ресурса /URI, который со временем изменится, я бы пришел к выводу, что версии API не должны храниться в ресурсных URI в течение длительного времени, что означает, что URI ресурсов, которые API пользователи могут зависеть от того, должны ли быть постоянными ссылками.

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

Несколько мыслей об обслуживании версий API, срок действия которых на них. Все платформы программирования/языки, обычно используемые для реализации веб-сервисов (Java,.NET, PHP, Perl, Rails и т.д.), Позволяют легко привязывать конечные точки веб-сервисов к базовому URI. Таким образом легко собрать и сохранить коллекцию файлов/классов/методов в разных версиях API.

От пользователей API POV также легче работать с конкретной версией API и привязываться к определенной версии API, когда это очевидно, но только в течение ограниченного времени, то есть во время разработки.

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

Однако, с версиями API, хорошо видимыми в URI, существует оговорка: можно также возразить против этого подхода, поскольку история API становится видимой /aparent в дизайне URI и, следовательно, подвержена изменениям время, что противоречит рекомендациям REST. Я согласен!

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

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

  • привязка к определенной версии API (что становится очевидным), но только в течение ограниченного времени

Например, если API v3.0 является последней версией API, следующие два должны быть псевдонимами (например, вести себя одинаково со всеми запросами API):

http://shonzilla/api/customers/1234
http://shonzilla/api/v3.0/customers/1234
http://shonzilla/api/v3/customers/1234

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

http://shonzilla/api/v2.2/customers/1234
http://shonzilla/api/v2.0/customers/1234
http://shonzilla/api/v2/customers/1234
http://shonzilla/api/v1.1/customers/1234
http://shonzilla/api/v1/customers/1234

должен возвращать любой из кодов статуса 30x HTTP, которые указывают перенаправление, которые используются вместе с заголовком Location HTTP, который перенаправляет на соответствующую версию URI ресурса, которая остается таковой:

http://shonzilla/api/customers/1234

Существует, по меньшей мере, два кода статуса HTTP перенаправления, которые подходят для сценариев управления версиями API:

  • 301 Постоянно перемещается, указывая, что ресурс с запрошенным URI постоянно перемещается в другой URI (который должен быть постоянным значением экземпляра ресурса который не содержит информацию о версии API). Этот код состояния может использоваться для указания устаревшей/неподдерживаемой версии API, информирующей клиента API о замене версированного ресурса ресурса на постоянную ссылку ресурса.

  • 302 Найдено, указав, что запрашиваемый ресурс временно находится в другом месте, в то время как запрошенный URI может все еще поддерживаться. Этот код состояния может быть полезен, когда URI без версий временно недоступны и что запрос должен быть повторен с использованием адреса перенаправления (например, указывая на URI с встроенной версией APi), и мы хотим сказать клиентам продолжать использовать его (т.е. Permalinks).

  • другие сценарии можно найти в главе 3 перенаправления в HTTP 1.1 спецификации

Ответ 2

URL не должен содержать версии. Версия не имеет ничего общего с "идеей" ресурса, который вы запрашиваете. Вы должны попытаться представить URL-адрес как путь к концепции, которую хотите, а не как вернуть элемент. Версия диктует представление объекта, а не понятие объекта. Как говорили другие плакаты, вы должны указывать формат (включая версию) в заголовке запроса.

Если вы посмотрите на полный HTTP-запрос для URL-адресов, у которых есть версии, он выглядит так:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

Заголовок содержит строку, содержащую запрашиваемое представление ( "Accept: application/xml" ). Вот где должна идти версия. Кажется, все замалчивают тот факт, что вы можете хотеть одно и то же в разных форматах и ​​что клиент должен иметь возможность спросить, чего он хочет. В приведенном выше примере клиент запрашивает XML-представление XML ANY, а не истинное представление того, что он хочет. Сервер, теоретически, мог бы вернуть что-то совершенно не связанное с запросом, если оно было XML, и его нужно было бы проанализировать, чтобы понять, что это неправильно.

Лучший способ:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Далее, скажем, клиенты считают, что XML слишком многословный, и теперь им нужен JSON. В других примерах у вас должен быть новый URL-адрес для одного и того же клиента, поэтому вы получите:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(или что-то подобное). Когда на самом деле, каждый HTTP-запрос содержит формат, который вы ищете:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

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

Есть много других преимуществ, и я обсуждаю некоторые из них здесь, в моем блоге: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Последний пример, показывающий, как плохо переносить версию в URL. Допустим, вам нужна часть информации внутри объекта, и вы проверили ваши различные объекты (клиенты - v3.0, заказы - v2.0, а объект shipto - v4.2). Вот скверный URL, который вы должны указать в клиенте:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

Ответ 3

Мы нашли практичным и полезным разместить версию в URL-адресе. Это позволяет легко понять, что вы используете с первого взгляда. Мы используем псевдоним /foo для/foo/(последние версии) для удобства использования, более короткие/чистые URL-адреса и т.д., Как предполагает принятый ответ.

Сохранение обратной совместимости навсегда часто является дорогостоящим и/или очень сложным. Мы предпочитаем давать предварительное уведомление об устаревании, переадресациях, предлагаемых здесь, документах и ​​других механизмах.

Ответ 4

Я согласен с тем, что правильное представление ресурсов лучше соответствует методу REST... но одна большая проблема с пользовательскими типами MIME (или типами MIME, которые добавляют параметр версии) - это плохая поддержка для записи заголовков Accept и Content-Type в HTML и JavaScript.

Например, невозможно создать IMO для POST со следующими заголовками в форматах HTML5, чтобы создать ресурс:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

Это связано с тем, что атрибут HTML5 enctype является перечислением, поэтому ничего, кроме обычных application/x-www-formurlencoded, multipart/form-data и text/plain, недействительны.

... и я уверен, что он поддерживается во всех браузерах в HTML4 (у которого есть более слабый атрибут encytpe, но будет проблемой реализации браузера в отношении того, был ли перенаправлен тип MIME)

Из-за этого я теперь считаю, что наиболее подходящий способ для версии - через URI, но я согласен, что это не "правильный" способ.

Ответ 5

Поместите свою версию в URI. Одна версия API не всегда поддерживает типы из другого, поэтому аргумент, что ресурсы просто переносятся из одной версии в другую, просто неверен. Это не то же самое, что переключение формата из XML в JSON. Типы могут отсутствовать, или они могут быть изменены семантически.

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

Ответ 6

Есть несколько мест, в которых вы можете управлять версиями в REST API:

  • Как отмечено, в URI. Это может быть приемлемым и даже эстетически приятным, если перенаправления и т.д. Используются хорошо.

  • В заголовке Accepts: так что версия находится в файле. Как "mp3" против "mp4". Это также будет работать, хотя IMO работает немного хуже, чем...

  • В самом ресурсе. Многие форматы файлов имеют встроенные в них номера версий, как правило, в заголовке; это позволяет более новому программному обеспечению "просто работать", понимая все существующие версии типа файлов, в то время как более старое программное обеспечение может использовать, если указана неподдерживаемая (более новая) версия. В контексте REST API это означает, что ваши URI никогда не должны меняться, просто ваш ответ на конкретную версию данных, которую вы передали.

Я вижу причины использовать все три подхода:

  • если вам нравится использовать новые API-интерфейсы "clean sweep" или для основных изменений версии, где вы хотите использовать такой подход.
  • если вы хотите, чтобы клиент знал, прежде чем он выполнит PUT/POST, будет ли он работать или нет.
  • если все в порядке, если клиент должен выполнить PUT/POST, чтобы узнать, будет ли он работать.

Ответ 7

Версии вашего REST API аналогичны версии любого другого API. Незначительные изменения могут быть сделаны на месте, для крупных изменений может потребоваться совершенно новый API. Самый простой для вас - начинать с нуля каждый раз, когда при установке версии в URL-адрес имеет смысл. Если вы хотите облегчить жизнь клиенту, вы пытаетесь поддерживать обратную совместимость, которую вы можете сделать с устаревшей (постоянной переадресацией), ресурсами в нескольких версиях и т.д. Это более сложно и требует больших усилий. Но это также то, что рекомендует REST в "Cool URIs, не меняются".

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