rest versioning

rest - ¿Mejores prácticas para la creación de versiones de API?



rest version (7)

Esta es una buena y una pregunta difícil. El tema del diseño de URI es, al mismo tiempo, la parte más prominente de una API REST y , por lo tanto, un compromiso potencialmente a largo plazo con los usuarios de esa API .

Dado que la evolución de una aplicación y, en menor medida, su API es un hecho de la vida y que es incluso similar a la evolución de un producto aparentemente complejo como un lenguaje de programación, el diseño de URI debe tener restricciones menos naturales y debe conservarse con el tiempo Cuanto más larga sea la vida útil de la aplicación y la API, mayor será el compromiso con los usuarios de la aplicación y la API.

Por otro lado, otro hecho de la vida es que es difícil prever todos los recursos y sus aspectos que se consumirían a través de la API. Por suerte, no es necesario diseñar la API completa que se utilizará hasta Apocalypse . Es suficiente definir correctamente todos los puntos finales de recursos y el esquema de direccionamiento de cada recurso y cada instancia de recurso.

Con el tiempo, es posible que deba agregar nuevos recursos y nuevos atributos a cada recurso en particular, pero el método que los usuarios de API siguen para acceder a un recurso en particular no debe cambiar una vez que el esquema de direccionamiento de recursos se haga público y, por lo tanto, definitivo.

Este método se aplica a la semántica del verbo HTTP (por ejemplo, PUT siempre debe actualizar / reemplazar) y los códigos de estado HTTP que se admiten en las versiones anteriores de la API (deben seguir funcionando para que los clientes de la API que han trabajado sin intervención humana puedan seguir trabajando) como eso).

Además, dado que la incorporación de la versión de API en el URI interrumpiría el concepto de hipermedia como motor del estado de la aplicación (establecido en la disertación de PhD de Roy T. Fieldings) al tener una dirección de recurso / URI que cambiaría con el tiempo, concluiría que el API las versiones no deben mantenerse en los URI de recursos durante mucho tiempo, lo que significa que los URI de recursos de los que pueden depender los usuarios de la API deben ser los enlaces permanentes .

Claro, es posible incrustar la versión de la API en el URI base, pero solo para usos razonables y restringidos, como la depuración de un cliente de la API que funciona con la nueva versión de la API. Estas API versionadas deben tener un límite de tiempo y estar disponibles solo para grupos limitados de usuarios de API (como durante betas cerradas) De lo contrario, te comprometes donde no deberías.

Un par de pensamientos sobre el mantenimiento de las versiones de API que tienen fecha de vencimiento. Todas las plataformas / lenguajes de programación comúnmente utilizados para implementar servicios web (Java, .NET, PHP, Perl, Rails, etc.) permiten unir fácilmente los puntos finales de los servicios web a un URI base. De esta manera, es fácil recopilar y mantener una colección de archivos / clases / métodos separados a través de diferentes versiones de API .

Desde el POV de los usuarios de la API, también es más fácil trabajar y vincularse a una versión particular de la API cuando es obvio, pero solo por tiempo limitado, es decir, durante el desarrollo.

Desde el punto de vista del mantenedor de API, es más fácil mantener diferentes versiones de API en paralelo utilizando sistemas de control de origen que funcionan predominantemente en archivos como la unidad más pequeña de versiones (código fuente).

Sin embargo, con las versiones de API claramente visibles en URI hay una advertencia: uno también podría objetar este enfoque, ya que el historial de API se hace visible / aparente en el diseño de URI y, por lo tanto, es propenso a cambios en el tiempo que van en contra de las pautas de REST. ¡Estoy de acuerdo!

La forma de sortear esta objeción razonable es implementar la última versión de la API bajo el URI base de la API sin versión. En este caso, los desarrolladores de clientes API pueden elegir entre:

  • Desarrolle en contra de la última (comprometiéndose a mantener la aplicación protegiéndola de eventuales cambios en la API que podrían romper su cliente API mal diseñado ).

  • enlazar a una versión específica de la API (que se vuelve aparente) pero solo por un tiempo limitado

Por ejemplo, si API v3.0 es la última versión de API, los dos siguientes deberían ser alias (es decir, comportarse de manera idéntica a todas las solicitudes de API):

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

Además, los clientes de API que aún intentan apuntar a la API antigua deben ser informados para usar la última versión de API anterior, si la versión de API que están usando está obsoleta o ya no es compatible . Así que accede a cualquiera de los URI obsoletos como estos:

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

debe devolver cualquiera de los códigos de estado HTTP 30x que indican la redirección que se usa junto con el encabezado HTTP de la Location que redirige a la versión apropiada del URI del recurso, que sigue siendo este:

http://shonzilla/api/customers/1234

Hay al menos dos códigos de estado HTTP de redirección que son apropiados para los escenarios de versión de API:

  • 301 Movido permanentemente, lo que indica que el recurso con un URI solicitado se mueve permanentemente a otro URI (que debe ser un enlace permanente de la instancia del recurso que no contiene información de la versión de la API). Este código de estado puede usarse para indicar una versión de API obsoleta / no compatible, informando al cliente de API que un URI de recurso versionado ha sido reemplazado por un enlace permanente de recursos .

  • 302 Se encontró que indica que el recurso solicitado está ubicado temporalmente en otra ubicación, mientras que el URI solicitado todavía puede ser compatible. Este código de estado puede ser útil cuando los URI sin versión no están disponibles temporalmente y que una solicitud debe repetirse usando la dirección de redirección (por ejemplo, apuntando al URI con la versión APi incorporada) y queremos que los clientes sigan usándola (es decir, enlaces permanentes).

  • Se pueden encontrar otros escenarios en el capítulo de Redirección 3xx de la especificación HTTP 1.1.

¿Se conocen procedimientos prácticos o mejores prácticas para la creación de versiones de la API REST del servicio web?

Me he dado cuenta de que AWS realiza el control de versiones mediante la URL del punto final . ¿Es esta la única manera o hay otras maneras de lograr el mismo objetivo? Si hay múltiples formas, ¿cuáles son los méritos de cada forma?


Estoy de acuerdo en que la versión de la representación de recursos sigue mejor el enfoque REST ... pero, un gran problema con los tipos MIME personalizados (o tipos MIME que añaden un parámetro de versión) es el mal soporte para escribir en los encabezados Aceptar y Tipo de Contenido en HTML y JavaScript

Por ejemplo, no es posible realizar IMO en POST con los siguientes encabezados en formularios HTML5 para crear un recurso:

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

Esto se debe a que el atributo enctype HTML5 es una enumeración, por lo tanto, cualquier otra cosa que no sea la application/x-www-formurlencoded , multipart/form-data y text/plain no son válidos.

... ni estoy seguro de que sea compatible con todos los navegadores en HTML4 (que tiene un atributo encytpe más laxo, pero sería un problema de implementación del navegador en cuanto a si se reenvió el tipo MIME)

Debido a esto, ahora siento que la forma más adecuada de obtener una versión es a través de la URI, pero acepto que no es la forma "correcta".


Hay algunos lugares en los que puede realizar la creación de versiones en una API REST:

  1. Como se ha señalado, en la URI. Esto puede ser manejable e incluso estéticamente agradable si se utilizan bien las redirecciones y similares.

  2. En el encabezado Acepta: así que la versión está en el tipo de archivo. Me gusta ''mp3'' vs ''mp4''. Esto también funcionará, aunque IMO funciona un poco menos bien que ...

  3. En el propio recurso. Muchos formatos de archivo tienen sus números de versión incrustados, normalmente en el encabezado; esto permite que el software más nuevo "simplemente funcione" al comprender todas las versiones existentes del tipo de archivo, mientras que el software más antiguo puede despojarse si se especifica una versión no compatible (más nueva). En el contexto de una API REST, significa que sus URI nunca tienen que cambiar, solo su respuesta a la versión particular de los datos que le entregaron.

Puedo ver razones para usar los tres enfoques:

  1. si le gusta realizar nuevas API de ''barrido limpio'', o para cambios de versión importantes en los que desea tal enfoque.
  2. si desea que el cliente sepa antes de hacer un PUT / POST si va a funcionar o no.
  3. si está bien si el cliente tiene que hacer su PUT / POST para averiguar si va a funcionar.

La URL NO debe contener las versiones. La versión no tiene nada que ver con la "idea" del recurso que está solicitando. Debe tratar de pensar que la URL es una ruta al concepto que desea, no cómo desea que se devuelva el elemento. La versión dicta la representación del objeto, no el concepto del objeto. Como han dicho otros carteles, debe especificar el formato (incluida la versión) en el encabezado de la solicitud.

Si observa la solicitud HTTP completa de las URL que tienen versiones, se ve así:

(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>

El encabezado contiene la línea que contiene la representación que solicita ("Aceptar: aplicación / xml"). Ahí es donde debe ir la versión. Todos parecen pasar por alto el hecho de que es posible que desee lo mismo en diferentes formatos y que el cliente debería poder pedir lo que quiere. En el ejemplo anterior, el cliente solicita CUALQUIER representación XML del recurso, no realmente la verdadera representación de lo que quiere. El servidor podría, en teoría, devolver algo completamente ajeno a la solicitud, siempre y cuando fuera XML y tendría que analizarse para darse cuenta de que está mal.

Una mejor manera es:

(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>

Además, digamos que los clientes piensan que el XML es demasiado detallado y ahora quieren JSON en su lugar. En los otros ejemplos, tendría que tener una nueva URL para el mismo cliente, por lo que terminaría con:

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

(o algo similar). Cuando, de hecho, cada solicitud HTTP contiene el formato que está buscando:

(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"} }

Con este método, tiene mucha más libertad en el diseño y en realidad está siguiendo la idea original de REST. Puede cambiar las versiones sin interrumpir a los clientes, o cambiar de manera incremental los clientes a medida que se modifican las API. Si elige dejar de admitir una representación, puede responder a las solicitudes con un código de estado HTTP o códigos personalizados. El cliente también puede verificar que la respuesta está en el formato correcto y validar el XML.

Hay muchas otras ventajas y discuto algunas de ellas aquí en mi blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Un último ejemplo para mostrar cómo poner la versión en la URL es malo. Digamos que quieres algo de información dentro del objeto, y has versionado varios objetos (los clientes son v3.0, los pedidos son v2.0 y shipto object es v4.2). Aquí está la URL desagradable que debe proporcionar en el cliente:

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


La versión de su API REST es análoga a la versión de cualquier otra API. Se pueden hacer cambios menores en el lugar, los cambios importantes pueden requerir una API completamente nueva. Lo más fácil para usted es comenzar desde cero cada vez, que es cuando colocar la versión en la URL tiene más sentido. Si desea hacer la vida más fácil para el cliente, intente mantener la compatibilidad con versiones anteriores, lo que puede hacer con la desaprobación (redireccionamiento permanente), los recursos en varias versiones, etc. Esto es más delicado y requiere más esfuerzo. Pero también es lo que REST alienta en "Cool URIs no cambian".

Al final, es como cualquier otro diseño de API. Pesar el esfuerzo contra la conveniencia del cliente. Considere la posibilidad de adoptar un control de versiones semántico para su API, lo que deja claro para sus clientes la compatibilidad con versiones anteriores de su nueva versión.


Nos pareció práctico y útil poner la versión en la URL. Le facilita saber qué está usando de un vistazo. Hacemos alias / foo a / foo / (últimas versiones) para facilitar el uso, URL más cortas / más limpias, etc., como sugiere la respuesta aceptada.

Mantener la compatibilidad hacia atrás para siempre es a menudo prohibitivo y / o muy difícil. Preferimos dar aviso avanzado de desaprobación, redirecciones como se sugiere aquí, documentos y otros mecanismos.


Pon tu versión en la URI. Una versión de una API no siempre admitirá los tipos de otra, por lo que el argumento de que los recursos simplemente se migran de una versión a otra es simplemente erróneo. No es lo mismo que cambiar el formato de XML a JSON. Es posible que los tipos no existan o que hayan cambiado semánticamente.

Las versiones son parte de la dirección del recurso. Estás enrutando de una API a otra. No es útil ocultar el direccionamiento en el encabezado.