SlideShare uma empresa Scribd logo
1 de 96
REST API Versioning Techniques
Arquitecto de Soluciones de Software
Rodrigo Liberoff
with ASP.NET Web API
“Si al principio no tienes
éxito, llámalo versión 1.0.”
― Anónimo - Desconocido
Introducción
Google
Youtube
Facebook
Wikipedia
TwitterLinkedIn
Wordpress
Yahoo
El Mundo
El desarrollo de Web APIs está explotando…
…y las compañías están exigiéndolo.
Los creadores de HTTP pensaron mucho sobre esto y
sobre cómo diseñar con miras a la evolución.
La pregunta no es “si evoluciona”...
…la pregunta es “cómo evolucionará”.
Conceptos
¿QUÉES…?
¿QUÉES…?
¿QUÉES…?
¿QUÉES…?
¿QUÉES…?
Ejemplo
Ejemplo
¿QUÉSON…?
Ejemplos
¿QUÉES…?
http://geek-and-poke.com/geekandpoke/2013/6/14/insulting-made-easy
¿QUÉES…?
¿QUÉES…?
Versionando un Web API
En general, se considera que la combinación de
descubrimiento de recursos en tiempo de ejecución,
mensajes auto-descriptivos y clientes reactivos son críticos
para conseguir un Web API evolucionable.
También se considera que, aunque son conceptos difíciles
de entender e implementar, la flexibilidad y escalabilidad
que aportan supera con creces su costo.
En general, en la filosofía REST, versionar recursos se
considera una mala práctica o evidencia de un pobre
diseño.
TIPO DESCRIPCIÓN
Payload La versión es parte del mensaje.
Query String
La versión es un parámetro que forma parte de la URI
del recurso.
URL Suffix
La versión es parte del URI, y se anexa al final del
mismo.
Custom Header
La versión es suministrada en una cabecera propia no
estándar.
URL La versión es parte indirecta del URI del recurso.
Media Type
Content Type
La versión es suministrada como el media type
esperado de la representación del recurso.
TIPO DESCRIPCIÓN
Payload La versión es parte del mensaje.
Query String
La versión es un parámetro que forma parte de la URI
del recurso.
URL Suffix
La versión es parte del URI, y se anexa al final del
mismo.
Ejemplos
<xml>
<version>2</version>
...
</xml>
http://MyCoolSite/api/recurso?v=2
http://MyCoolSite/api/recurso?v=1_1
http://MyCoolSite/api/recurso.v2
http://MyCoolSite/api/recurso.v1_1
Ejemplos
GET http://MyCoolSite/api/recurso HTTP/1.1
...
api-version: 2
...
http://MyCoolSite/api/v2/recurso
http://MyCoolSite/api/v1.1/recurso
GET http://MyCoolSite/api/recurso HTTP/1.1
...
Accept: application/vnd.company.site.api.resource.v2+json
...
Ejemplos
www.facebook.com/v2.7/dialog/oauth
www.facebook.com/v2.7/plugins/
graph.facebook.com/v2.7/
Ejemplos
https://api.twitter.com/1.1/statuses/user_timeline.json
https://api.twitter.com/1.1/direct_messages/destroy.json
https://api.twitter.com/1.1/users/report_spam.json
Ejemplos
Accept: application/vnd.github.v3+json
Accept: application/vnd.github.loki-preview+json
Implementación
Version del Controlador por Nombre
public class DummyController : ApiController
{
...
}
public class DummyV2Controller : ApiController
{
...
}
public class V2DummyController : ApiController
{
...
}
public class DummyControllerV2 : ApiController
{
...
}
public class DummyControllerV2 : ApiController
{
// Este controlador no es válido, porque no cumple con la convención de ASP.NET MVC y
// ASP.NET Web API sobre nombres para controladores.
...
}
Versión de Controlador por Espacio de Nombres
namespace My.Cool.Api.V1
{
public class DummyController : ApiController
{
...
}
}
namespace My.Cool.Api.V2
{
public class DummyController : ApiController
{
...
}
}
Código para los Ejemplos
public class Console
{
public int Id { get; set; }
public string Name { get; set; }
}
public class NexGenConsole : Console
{
public bool IsNexGen { get; set; }
}
Código para los Ejemplos
public class ConsoleController : ApiController
{
public virtual IEnumerable<Console> GetConsoles
{
get { return ... }
}
public virtual Console GetConsole(int id)
{
return new Console { Id = id, Name = @"PS3" };
}
}
public class ConsoleV2Controller : ConsoleController
{
public override Console GetConsole(int id)
{
return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true };
}
}
Código para los Ejemplos
internal static class VersionFinder
{
public static int GetVersionFromRequestData(HttpRequestMessage request) {...}
private static bool NeedsUriVersioning(HttpRequestMessage request, out string version)
{ ... }
private static bool NeedsHeaderVersioning(HttpRequestMessage request, out string version)
{ ... }
private static bool NeedsAcceptVersioning(HttpRequestMessage request, out string version)
{ ... }
private static int VersionToInt(string versionString) { ... }
}
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
Versionado a través de Enrutamiento por Convención
public static class WebApiConfig
{
public static void Register(HttpConfiguration config, IDependencyResolver dependencyResolver)
{
if (config != null)
{
...
config.Services.Replace(typeof(IHttpControllerSelector),
new VersionAwareControllerSelector(config));
...
}
}
}
Versionado a través de Enrutamiento por Convención
public static class WebApiConfig
{
public static void Register(HttpConfiguration config, IDependencyResolver dependencyResolver)
{
if (config != null)
{
...
config.Routes.MapHttpRoute(name: @"VersionedApi",
routeTemplate: @"api/v{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { version = @"[1-9]+[d]*" });
config.Routes.MapHttpRoute(name: @"DefaultApi",
routeTemplate: @"api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
...
}
}
}
DEMO 1
Versionado a través de Enrutamiento por Atributos
…Sino que se
Versionado a través de Enrutamiento por Atributos
Uno de los primeros pasos es decorar los controladores
con los atributos de enrutamiento apropiados.
[RoutePrefix(@"api/v1")]
public class ConsoleAttributeController : ApiController
{
[Route(@"consoles")]
public virtual IEnumerable<Console> Console RetrieveConsoles()
{
return ...
}
[Route(@"consoles/{id:int}")]
public virtual Console RetrieveConsole(int id)
{
return new Console { Id = id, Name = @"PS3" };
}
}
Versionado a través de Enrutamiento por Atributos
[RoutePrefix(@"api/v2")]
public class ConsoleAttributeV2Controller : ConsoleAttributeController
{
[Route(@"consoles/{id:int}")]
public override Console RetrieveConsole(int id)
{
return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true };
}
}
Y ya sólo con esto, se tendría versionado mediante URL,
ya que la declaración de la ruta directamente en el
controlador o la acción, es la naturaleza misma del
enrutamiento por atributo.
DEMO 2
Versionado a través de Enrutamiento por Atributos
Soportar las modalidades de custom header y custom
media type, simplemente requiere identificar el origen
del dato correspondiente a la versión.
Versionado a través de Enrutamiento por Atributos
Sin embargo, es necesario informar a los atributos de
enrutamiento de la existencia de una restricción por
versión, para lo cual:
Versionado a través de Enrutamiento por Atributos
internal class VersionConstraint : IHttpRouteConstraint
{
private readonly int allowedVersion;
public VersionConstraint(int version)
{
this.allowedVersion = version;
}
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
return request == null ?
false :
this.allowedVersion == VersionFinder.GetVersionFromRequestData(request);
}
}
Versionado a través de Enrutamiento por Atributos
internal class VersionedRouteAttribute : RouteFactoryAttribute
{
public VersionedRouteAttribute(string template)
: base(template)
{
this.Order = -1;
}
public int Version { get; set; }
public override IDictionary<string, object> Constraints
{
get
{
return new HttpRouteValueDictionary
{
{ string.Empty, new VersionConstraint(this.Version) }
};
}
}
}
Versionado a través de Enrutamiento por Atributos
Finalmente, decoramos los controladores con el nuevo
atributo VersionedRouteAttribute.
[RoutePrefix(@"api")]
public class ConsoleAttributeController : ApiController
{
[HttpGet, Route(@“v1/consoles")]
[VersionedRoute(@"consoles", Version = 1)]
public virtual IEnumerable<Console> Console Get()
{
return ...
}
[HttpGet, Route(@“v1/consoles/{id:int}")]
[VersionedRoute(@“consoles/{id:int}", Version = 1)]
public virtual Console Get(int id)
{
return new Console { Id = id, Name = @"PS3" };
}
}
Versionado a través de Enrutamiento por Atributos
[RoutePrefix(@"api")]
public class ConsoleAttributeV2Controller : ConsoleAttributeController
{
[HttpGet, Route(@"v2/consoles")]
[VersionedRoute(@"consoles", Version = 2)]
public override IEnumerable<Console> RetrieveConsoles()
{
return base.RetrieveConsoles();
}
[HttpGet, Route(@"v2/consoles/{id:int}")]
[VersionedRoute(@"consoles/{id:int}", Version = 2)]
public override Console Get(int id)
{
return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true };
}
}
Y ahora se cuenta con versionado por URL, plus
versionado por custom header y custom media type.
DEMO 3
RECOMENDACIONES
Y
BUENAS PRÁCTICAS
Encontraremos diferentes
posiciones filosóficas sobre la
“manera correcta” de alcanzar
REST, sobre qué es RESTful, y
qué no lo es.
Desafortunadamente, lo
filosófico pasa a lo religioso y
se pierde el foco sobre cuál
debería ser el objetivo real:
construir software que
funcione y un API coherente
que permita consumirle e
integrarle fácilmente.
http://shonzilla/api/customers/1234
http://shonzilla/api/v3.0/customers/1234
http://shonzilla/api/v3/customers/1234
Literatura y Bibliografía
Preguntas
¡GRACIAS!
@rliberoff
https://es.linkedin.com/in/rliberoff
http://www.commitstrip.com/en/2013/08/20/numeros-de-version/

Mais conteúdo relacionado

Mais procurados

Presentation on Android
Presentation on AndroidPresentation on Android
Presentation on AndroidNausad Ahamed
 
Introduction to fragments in android
Introduction to fragments in androidIntroduction to fragments in android
Introduction to fragments in androidPrawesh Shrestha
 
Introduction to ajax
Introduction to ajaxIntroduction to ajax
Introduction to ajaxNir Elbaz
 
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOS
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOSSoftware architectural design patterns(MVC, MVP, MVVM, VIPER) for iOS
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOSJinkyu Kim
 
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptx
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptxGetting started with Next.js - IM Tech Meetup - Oct 2022.pptx
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptxIlesh Mistry
 
Introduction to React
Introduction to ReactIntroduction to React
Introduction to ReactRob Quick
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJSDavid Parsons
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux jsCitrix
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJSKnoldus Inc.
 
Android service, aidl - day 1
Android service, aidl - day 1Android service, aidl - day 1
Android service, aidl - day 1Utkarsh Mankad
 
QA. Load Testing
QA. Load TestingQA. Load Testing
QA. Load TestingAlex Galkin
 

Mais procurados (20)

Presentation on Android
Presentation on AndroidPresentation on Android
Presentation on Android
 
Introduction to fragments in android
Introduction to fragments in androidIntroduction to fragments in android
Introduction to fragments in android
 
React js for beginners
React js for beginnersReact js for beginners
React js for beginners
 
Introduction to ajax
Introduction to ajaxIntroduction to ajax
Introduction to ajax
 
Pwa.pptx
Pwa.pptxPwa.pptx
Pwa.pptx
 
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOS
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOSSoftware architectural design patterns(MVC, MVP, MVVM, VIPER) for iOS
Software architectural design patterns(MVC, MVP, MVVM, VIPER) for iOS
 
Reactjs
ReactjsReactjs
Reactjs
 
Web Accessibility
Web AccessibilityWeb Accessibility
Web Accessibility
 
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptx
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptxGetting started with Next.js - IM Tech Meetup - Oct 2022.pptx
Getting started with Next.js - IM Tech Meetup - Oct 2022.pptx
 
Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
 
Java script
Java scriptJava script
Java script
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux js
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
Node js Introduction
Node js IntroductionNode js Introduction
Node js Introduction
 
Android service, aidl - day 1
Android service, aidl - day 1Android service, aidl - day 1
Android service, aidl - day 1
 
Load testing with J meter
Load testing with J meterLoad testing with J meter
Load testing with J meter
 
QA. Load Testing
QA. Load TestingQA. Load Testing
QA. Load Testing
 
React JS part 1
React JS part 1React JS part 1
React JS part 1
 
Angular introduction students
Angular introduction studentsAngular introduction students
Angular introduction students
 

Destaque

Despliegue de aplicaciones en Azure Web Apps
Despliegue de aplicaciones en Azure Web AppsDespliegue de aplicaciones en Azure Web Apps
Despliegue de aplicaciones en Azure Web AppsHernan Guzman
 
¿Qué es un hackathon y por qué deberías asistir?
¿Qué es un hackathon y por qué deberías asistir?¿Qué es un hackathon y por qué deberías asistir?
¿Qué es un hackathon y por qué deberías asistir?Adolfo Sanz De Diego
 
Desarrollando un API con REST
Desarrollando un API con RESTDesarrollando un API con REST
Desarrollando un API con RESTAlex Puig
 
Construye un backend para tus app móviles con con ASP.NET Web Api
Construye un backend para tus app móviles con con ASP.NET Web ApiConstruye un backend para tus app móviles con con ASP.NET Web Api
Construye un backend para tus app móviles con con ASP.NET Web ApiHernan Guzman
 
Inventando métricas en Social Media
Inventando métricas en Social MediaInventando métricas en Social Media
Inventando métricas en Social MediaAlex Puig
 

Destaque (6)

Despliegue de aplicaciones en Azure Web Apps
Despliegue de aplicaciones en Azure Web AppsDespliegue de aplicaciones en Azure Web Apps
Despliegue de aplicaciones en Azure Web Apps
 
¿Qué es un hackathon y por qué deberías asistir?
¿Qué es un hackathon y por qué deberías asistir?¿Qué es un hackathon y por qué deberías asistir?
¿Qué es un hackathon y por qué deberías asistir?
 
Desarrollando un API con REST
Desarrollando un API con RESTDesarrollando un API con REST
Desarrollando un API con REST
 
Construye un backend para tus app móviles con con ASP.NET Web Api
Construye un backend para tus app móviles con con ASP.NET Web ApiConstruye un backend para tus app móviles con con ASP.NET Web Api
Construye un backend para tus app móviles con con ASP.NET Web Api
 
Inventando métricas en Social Media
Inventando métricas en Social MediaInventando métricas en Social Media
Inventando métricas en Social Media
 
Servidor API REST con Node.js
Servidor API REST con Node.jsServidor API REST con Node.js
Servidor API REST con Node.js
 

Semelhante a REST Versioning Architecture with ASP.NET MVC Web API v1.2

Presentacion #bbmnk
Presentacion #bbmnkPresentacion #bbmnk
Presentacion #bbmnkJuan Miqueo
 
App engine
App engineApp engine
App engineThirdWay
 
Aprendiendo AWS Lambda con API Gateway y DynamoDB
Aprendiendo AWS Lambda con API Gateway y DynamoDBAprendiendo AWS Lambda con API Gateway y DynamoDB
Aprendiendo AWS Lambda con API Gateway y DynamoDBAbimael Desales López
 
Curso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCurso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCarlos Azaustre
 
Tecnologías para microservicios
Tecnologías para microserviciosTecnologías para microservicios
Tecnologías para microserviciosPedro J. Molina
 
Hands-on Spring 3: The next generation
Hands-on Spring 3: The next generationHands-on Spring 3: The next generation
Hands-on Spring 3: The next generationSergi Almar i Graupera
 
Intro a ASP.NET
Intro a ASP.NETIntro a ASP.NET
Intro a ASP.NETwilliamsm
 
Desarrollo web con_asp.net 2.1
Desarrollo web con_asp.net 2.1Desarrollo web con_asp.net 2.1
Desarrollo web con_asp.net 2.1JuanCarlos1937
 
App todo gas: WordPress no es solo para web
App todo gas: WordPress no es solo para webApp todo gas: WordPress no es solo para web
App todo gas: WordPress no es solo para webPaco Marchante
 
Appcircus Academy: Integración de Social Media en Android
Appcircus Academy: Integración de Social Media en AndroidAppcircus Academy: Integración de Social Media en Android
Appcircus Academy: Integración de Social Media en AndroidAlberto Ruibal
 
WORKSHOP I: Introducción a API REST
WORKSHOP I: Introducción a API RESTWORKSHOP I: Introducción a API REST
WORKSHOP I: Introducción a API RESTBEEVA_es
 

Semelhante a REST Versioning Architecture with ASP.NET MVC Web API v1.2 (20)

Presentacion #bbmnk
Presentacion #bbmnkPresentacion #bbmnk
Presentacion #bbmnk
 
App engine
App engineApp engine
App engine
 
Servicios web
Servicios webServicios web
Servicios web
 
Aprendiendo AWS Lambda con API Gateway y DynamoDB
Aprendiendo AWS Lambda con API Gateway y DynamoDBAprendiendo AWS Lambda con API Gateway y DynamoDB
Aprendiendo AWS Lambda con API Gateway y DynamoDB
 
Curso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCurso de Desarrollo Web de Platzi
Curso de Desarrollo Web de Platzi
 
Tecnologías para microservicios
Tecnologías para microserviciosTecnologías para microservicios
Tecnologías para microservicios
 
Hands-on Spring 3: The next generation
Hands-on Spring 3: The next generationHands-on Spring 3: The next generation
Hands-on Spring 3: The next generation
 
Api rest client en Android
Api rest client en AndroidApi rest client en Android
Api rest client en Android
 
Intro a ASP.NET
Intro a ASP.NETIntro a ASP.NET
Intro a ASP.NET
 
Ajax
AjaxAjax
Ajax
 
Charla
CharlaCharla
Charla
 
Desarrollo web con_asp.net 2.1
Desarrollo web con_asp.net 2.1Desarrollo web con_asp.net 2.1
Desarrollo web con_asp.net 2.1
 
App todo gas: WordPress no es solo para web
App todo gas: WordPress no es solo para webApp todo gas: WordPress no es solo para web
App todo gas: WordPress no es solo para web
 
Aplicaciones Web
Aplicaciones WebAplicaciones Web
Aplicaciones Web
 
Desarrollo de Aplicaciones Web 2.0 con GWT
Desarrollo de Aplicaciones Web 2.0 con GWTDesarrollo de Aplicaciones Web 2.0 con GWT
Desarrollo de Aplicaciones Web 2.0 con GWT
 
Servicios web java, php, perl, google
Servicios web java, php, perl, googleServicios web java, php, perl, google
Servicios web java, php, perl, google
 
Desarrollo web
Desarrollo webDesarrollo web
Desarrollo web
 
Gwt III - Avanzado
Gwt III - AvanzadoGwt III - Avanzado
Gwt III - Avanzado
 
Appcircus Academy: Integración de Social Media en Android
Appcircus Academy: Integración de Social Media en AndroidAppcircus Academy: Integración de Social Media en Android
Appcircus Academy: Integración de Social Media en Android
 
WORKSHOP I: Introducción a API REST
WORKSHOP I: Introducción a API RESTWORKSHOP I: Introducción a API REST
WORKSHOP I: Introducción a API REST
 

REST Versioning Architecture with ASP.NET MVC Web API v1.2

  • 1. REST API Versioning Techniques Arquitecto de Soluciones de Software Rodrigo Liberoff with ASP.NET Web API
  • 2. “Si al principio no tienes éxito, llámalo versión 1.0.” ― Anónimo - Desconocido
  • 4.
  • 6. El desarrollo de Web APIs está explotando…
  • 7. …y las compañías están exigiéndolo.
  • 8.
  • 9. Los creadores de HTTP pensaron mucho sobre esto y sobre cómo diseñar con miras a la evolución.
  • 10.
  • 11. La pregunta no es “si evoluciona”... …la pregunta es “cómo evolucionará”.
  • 12.
  • 13.
  • 25.
  • 26.
  • 27.
  • 28.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38. En general, se considera que la combinación de descubrimiento de recursos en tiempo de ejecución, mensajes auto-descriptivos y clientes reactivos son críticos para conseguir un Web API evolucionable. También se considera que, aunque son conceptos difíciles de entender e implementar, la flexibilidad y escalabilidad que aportan supera con creces su costo.
  • 39. En general, en la filosofía REST, versionar recursos se considera una mala práctica o evidencia de un pobre diseño.
  • 40.
  • 41. TIPO DESCRIPCIÓN Payload La versión es parte del mensaje. Query String La versión es un parámetro que forma parte de la URI del recurso. URL Suffix La versión es parte del URI, y se anexa al final del mismo. Custom Header La versión es suministrada en una cabecera propia no estándar. URL La versión es parte indirecta del URI del recurso. Media Type Content Type La versión es suministrada como el media type esperado de la representación del recurso. TIPO DESCRIPCIÓN Payload La versión es parte del mensaje. Query String La versión es un parámetro que forma parte de la URI del recurso. URL Suffix La versión es parte del URI, y se anexa al final del mismo.
  • 42.
  • 44. Ejemplos GET http://MyCoolSite/api/recurso HTTP/1.1 ... api-version: 2 ... http://MyCoolSite/api/v2/recurso http://MyCoolSite/api/v1.1/recurso GET http://MyCoolSite/api/recurso HTTP/1.1 ... Accept: application/vnd.company.site.api.resource.v2+json ...
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54. Version del Controlador por Nombre public class DummyController : ApiController { ... } public class DummyV2Controller : ApiController { ... } public class V2DummyController : ApiController { ... } public class DummyControllerV2 : ApiController { ... } public class DummyControllerV2 : ApiController { // Este controlador no es válido, porque no cumple con la convención de ASP.NET MVC y // ASP.NET Web API sobre nombres para controladores. ... }
  • 55. Versión de Controlador por Espacio de Nombres namespace My.Cool.Api.V1 { public class DummyController : ApiController { ... } } namespace My.Cool.Api.V2 { public class DummyController : ApiController { ... } }
  • 56.
  • 57.
  • 58. Código para los Ejemplos public class Console { public int Id { get; set; } public string Name { get; set; } } public class NexGenConsole : Console { public bool IsNexGen { get; set; } }
  • 59. Código para los Ejemplos public class ConsoleController : ApiController { public virtual IEnumerable<Console> GetConsoles { get { return ... } } public virtual Console GetConsole(int id) { return new Console { Id = id, Name = @"PS3" }; } } public class ConsoleV2Controller : ConsoleController { public override Console GetConsole(int id) { return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true }; } }
  • 60. Código para los Ejemplos internal static class VersionFinder { public static int GetVersionFromRequestData(HttpRequestMessage request) {...} private static bool NeedsUriVersioning(HttpRequestMessage request, out string version) { ... } private static bool NeedsHeaderVersioning(HttpRequestMessage request, out string version) { ... } private static bool NeedsAcceptVersioning(HttpRequestMessage request, out string version) { ... } private static int VersionToInt(string versionString) { ... } }
  • 61. Versionado a través de Enrutamiento por Convención
  • 62. Versionado a través de Enrutamiento por Convención
  • 63. Versionado a través de Enrutamiento por Convención
  • 64.
  • 65.
  • 66. Versionado a través de Enrutamiento por Convención
  • 67. Versionado a través de Enrutamiento por Convención
  • 68. Versionado a través de Enrutamiento por Convención
  • 69. Versionado a través de Enrutamiento por Convención
  • 70. Versionado a través de Enrutamiento por Convención public static class WebApiConfig { public static void Register(HttpConfiguration config, IDependencyResolver dependencyResolver) { if (config != null) { ... config.Services.Replace(typeof(IHttpControllerSelector), new VersionAwareControllerSelector(config)); ... } } }
  • 71. Versionado a través de Enrutamiento por Convención public static class WebApiConfig { public static void Register(HttpConfiguration config, IDependencyResolver dependencyResolver) { if (config != null) { ... config.Routes.MapHttpRoute(name: @"VersionedApi", routeTemplate: @"api/v{version}/{controller}/{id}", defaults: new { id = RouteParameter.Optional }, constraints: new { version = @"[1-9]+[d]*" }); config.Routes.MapHttpRoute(name: @"DefaultApi", routeTemplate: @"api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }); ... } } }
  • 73. Versionado a través de Enrutamiento por Atributos …Sino que se
  • 74. Versionado a través de Enrutamiento por Atributos Uno de los primeros pasos es decorar los controladores con los atributos de enrutamiento apropiados. [RoutePrefix(@"api/v1")] public class ConsoleAttributeController : ApiController { [Route(@"consoles")] public virtual IEnumerable<Console> Console RetrieveConsoles() { return ... } [Route(@"consoles/{id:int}")] public virtual Console RetrieveConsole(int id) { return new Console { Id = id, Name = @"PS3" }; } }
  • 75. Versionado a través de Enrutamiento por Atributos [RoutePrefix(@"api/v2")] public class ConsoleAttributeV2Controller : ConsoleAttributeController { [Route(@"consoles/{id:int}")] public override Console RetrieveConsole(int id) { return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true }; } } Y ya sólo con esto, se tendría versionado mediante URL, ya que la declaración de la ruta directamente en el controlador o la acción, es la naturaleza misma del enrutamiento por atributo.
  • 77. Versionado a través de Enrutamiento por Atributos Soportar las modalidades de custom header y custom media type, simplemente requiere identificar el origen del dato correspondiente a la versión.
  • 78. Versionado a través de Enrutamiento por Atributos Sin embargo, es necesario informar a los atributos de enrutamiento de la existencia de una restricción por versión, para lo cual:
  • 79. Versionado a través de Enrutamiento por Atributos internal class VersionConstraint : IHttpRouteConstraint { private readonly int allowedVersion; public VersionConstraint(int version) { this.allowedVersion = version; } public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection) { return request == null ? false : this.allowedVersion == VersionFinder.GetVersionFromRequestData(request); } }
  • 80. Versionado a través de Enrutamiento por Atributos internal class VersionedRouteAttribute : RouteFactoryAttribute { public VersionedRouteAttribute(string template) : base(template) { this.Order = -1; } public int Version { get; set; } public override IDictionary<string, object> Constraints { get { return new HttpRouteValueDictionary { { string.Empty, new VersionConstraint(this.Version) } }; } } }
  • 81. Versionado a través de Enrutamiento por Atributos Finalmente, decoramos los controladores con el nuevo atributo VersionedRouteAttribute. [RoutePrefix(@"api")] public class ConsoleAttributeController : ApiController { [HttpGet, Route(@“v1/consoles")] [VersionedRoute(@"consoles", Version = 1)] public virtual IEnumerable<Console> Console Get() { return ... } [HttpGet, Route(@“v1/consoles/{id:int}")] [VersionedRoute(@“consoles/{id:int}", Version = 1)] public virtual Console Get(int id) { return new Console { Id = id, Name = @"PS3" }; } }
  • 82. Versionado a través de Enrutamiento por Atributos [RoutePrefix(@"api")] public class ConsoleAttributeV2Controller : ConsoleAttributeController { [HttpGet, Route(@"v2/consoles")] [VersionedRoute(@"consoles", Version = 2)] public override IEnumerable<Console> RetrieveConsoles() { return base.RetrieveConsoles(); } [HttpGet, Route(@"v2/consoles/{id:int}")] [VersionedRoute(@"consoles/{id:int}", Version = 2)] public override Console Get(int id) { return new NexGenConsole { Id = id, Name = @"PS4", IsNexGen = true }; } } Y ahora se cuenta con versionado por URL, plus versionado por custom header y custom media type.
  • 85. Encontraremos diferentes posiciones filosóficas sobre la “manera correcta” de alcanzar REST, sobre qué es RESTful, y qué no lo es. Desafortunadamente, lo filosófico pasa a lo religioso y se pierde el foco sobre cuál debería ser el objetivo real: construir software que funcione y un API coherente que permita consumirle e integrarle fácilmente.
  • 86.
  • 87.
  • 88.
  • 89.
  • 92.
  • 93.
  • 94.

Notas do Editor

  1. ¿Quién sabe qué es esto? Les presento a INTERNET, tal y como existía en su primera versión en 1977 cuando se llamaba ARPANET. En 1989, Tim Berners-Lee, un científico del CERN, inventó la World Wide Web, un sistema de acceso a los documentos vinculados a través de Internet. El acceso a estos documentos requería un protocolo para acceder (o navegar) hacia y entre ellos. Dicho protocolo se conoce hoy día como el protocolo de transferencia de hipertexto (HTTP). Este protocolo es en el centro de lo que impulsa sitios web y APIs Web.
  2. Este es Internet hoy día… En un principio podemos pensar que es una colección de sitios web, de páginas que podemos visitar, donde ver información útil, donde tenemos acceso a una ventana a la vida – que nos quieran mostrar – los demás. Es mucho más que eso… Todos esos sitios, en su mayoría, nos ofrecen un API para interactuar con ellos. Expanden los límites de su funcionalidad y de lo que ofrecen a través de un API que nos permite explotar aún más sus capacidades. La actual tendencia, en temas de API en Internet, son las Web API, también conocidas como API REST. Piensen en cualquiera de sus sitios web favoritos: Facebook, 9GAG, Twitter… todos exponen alguna forma de API, y actualmente todos son REST.
  3. ¿Saben de qué es la foto? Es de la misión Apollo 13, donde los ingenieros trataban de encontrar la manera de encajar un filtro de aire (CO2) de forma cúbica en un agujero de forma cilíndrica.
  4. El cambio es inevitable. Los cambios en una Web API son inevitables a medida que el conocimiento y la experiencia que se adquiere sobre un sistema y el negocio al que atienden mejora y se incrementa. Gestionar el impacto de estos cambios ciertamente puede ser un reto, sobre todo cuando aparece la amenaza de romper la integración que se tenga con los clientes del Web API.
  5. Estas son las preguntas alrededor de las cuales realizar el diseño de la Web API. A primera vista se podría pensar a un enfoque en cascada, pero no es en absoluto el caso. No se trata de diseñar todo el API antes de su construcción; no es una receta para la parálisis por análisis. Definitivamente, hay decisiones que debe tomar por adelantado, pero que son de alto nivel y se relacionan con el diseño del API general. No requieren entender o predecir todos los aspectos del sistema. Más bien, estas decisiones han de sentar las bases para que el API tenga la capacidad de evolucionar de forma iterativa y orgánica.
  6. De una petición a la siguiente, el estado de los recursos puede cambiar drásticamente, por lo que la representación que se devuelve puede ser muy diferente.
  7. Ejemplos de media types son: text/html text/xml image/png application/json Los media types son identificados con dos componentes: la primera corresponde al nivel superior que describe de forma genérica el tipo de información; y la segunda denominada subtipo y que describe el formato concreto y su estructura de datos esperada.
  8. Si bien el término REST se refiere originalmente a un conjunto de principios de arquitectura, hoy día se usa en un sentido más amplio para describir cualquier interfaz entre sistemas que utilice directamente el protocolo y los verbos HTTP para obtener datos o indicar la ejecución de operaciones sobre los datos, en cualquier formato (XML, JSON, etc) sin las abstracciones adicionales de los protocolos basados en patrones de intercambio de mensajes, como por ejemplo SOAP. A servicios web públicamente disponibles en Internet se les suele denominar como servicios RESTful. En esencia, hablar de Servicios REST o de Interfaces RESTful es hablar de lo mismo. En el mundo .NET solemos llamar a los servicios REST como Web APIs.
  9. En Web APIs se emplea permalinks para apuntar a la versión más reciente.
  10. Por ejemplo, hace unos años la representación estándar era XML, hoy es JSON, mañana puede ser otra cosa totalmente diferente…
  11. Esto en principio no es nada descabellado, ya que es justamente como funcionan los navegadores web.
  12. Desde la perspectiva de desarrollo de sistemas capaces de evolucionar, es útil tener considerar el versionado como el último recurso, cómo una admisión de fracaso. Asignar un “V1” al API inicial es proclamar (casi a gritos) que ya sabe que el API no puede evolucionar, y que surgirán cambios rompedores cuando se publique la versión “V2”. Sin embargo, todos somos humanos, y como tal nos equivocamos. En este caso, el emitir versiones es lo que hacemos cuando hemos agotado todas las demás opciones.
  13. URL  Es el mecanismo más directo y más popular. No obstante es uno de los que más molesta a los puristas de REST, ya que insisten (y tienen razón) que un URI debe referir a un recurso único y distinguido. Custom Header y Media Content  Un custom header permite preservar las URIs entre versiones, a pesar de ser efectivamente una duplicidad del comportamiento ya implementado y existente en HTTP de negociación del contenido (content negotiation). Lo anterior se evita justamente empleando la cabecera Accept de HTTP, con lo cual se evita la mencionada duplicidad. Sin embargo, en ambos casos, se fuerza a los clientes a conocer de ante mano que cabeceras deben enviar en una solicitud para especificar la correcta versión del recurso que desean acceder. Y Ciertamente, en ambos cosas, se permite preservar un conjunto limpio y claro de URLs hacia los recursos, pero agrega la necesidad de lidiar con la complejidad de servir diferentes versiones de contenido en algún punto del código del Web API. A veces, y dependiendo de la tecnología, esta complejidad termina llegando a la implementación del controlador, que se más allá de sólo encargarse del procesamiento y atención del recurso, termina también siendo responsable de determinar que versión del mismo (y su representación) enviar al llamador.
  14. Así, cambios en el código de un ensamblado (por ejemplo por corrección de errores o bugs) implicará un cambio de versión del mismo… …Pero no necesariamente implica un cambio en el API que contiene, ya que no hay cambios en la interfaz pública. Cambios en los recursos, sus representaciones o sus puntos de acceso si implicará un cambio del API, y también de su correspondiente ensamblado.
  15. Planos del proyecto cancelado para la autovía de la Bahía de Seattle.
  16. Coherente es la palabra clave a lo largo de esta parte de la presentación…
  17. El modelo de datos debe estar estabilizado antes de comenzar a diseñar el Web API. Esto ayudará a minimizar la generación espontanea y acelerada de versiones por imponderables o cosas “que no se pensaron o tuvieron en cuenta”. Si los consumidores invierten tiempo (y por ende dinero y esfuerzo) en escribir código que permita emplear nuestro Web API, entonces nosotros debemos hacer el máximo esfuerzo por no romper esa integración.
  18. Siempre manteniendo la línea de la coherencia. Ejemplo: combinar URL con custom media type. En la medida de lo posible evitar “1.1”, “2.2.3”. El software puede evolucionar en otras versiones debido a correcciones de errores o bugs, o mejoras de rendimiento, o cambios en sus tecnologías inherentes (como frameworks o bases de datos). Pero el Web API como tal, sus recursos y representaciones no han cambiado, por lo cual no requieren versionarse de nuevo. En los principios SOLID, el principio “Open\Closed” de Bertrand Meyer sugiere que las entidades y componentes de un software deben ser abiertas (open) para su extensión, y cerradas (closed) para su modificación. Esto llevado al contexto de los Web APIs tiene la implicación de que un recurso no debe cambiar arbitrariamente su firma, sino más bien extenderse (son sobrecargas por ejemplo) para soportar nuevos parámetros o restricciones.
  19. Por ejemplo, Facebook garantiza que cada versión de su Web API durará al menos dos años, y será removida pasados dos años tras la emisión de una versión más nueva. Por ejemplo, si la versión v2.3 es liberada el 25 de marzo, 2015, y la versión de v2.4 se libera el 7 de Agosto de 2015, entonces la versión v2.3 dejará de estar disponible el 7 de Agosto de 2017, exactamente dos años después de la emisión de la versión v2.4. Este tipo de políticas deben estar correctamente documentadas y públicas.
  20. Por ejemplo, si empleamos versionado por URL, cuando un consumidor accede a un recurso viejo, se podría contestar con códigos HTTP 301 o 302 según convenga, para informar del cambio de localización del recurso debido a una nueva versión del mismo. Así: 301 Moved Permanently  para indicar que el recurso en el URI de la solicitud se ha movido permanentemente a otro URI, el cual debería ser un permalink sin información de versión a la instancia de la nueva versión del recurso). Este código de estado puede emplearse para indicar una versión del Web API obsoleta o no soportada, informando al consumidor del reemplazo por la nueva versión. 302 Found  para indicar que el recurso solicitado está temporalmente localizado en otro sitio, y que por lo tanto el URI sigue siendo soportado. Este código de estado puede ser útil cuando URIs sin información de versión (permalinks) no estén disponibles y se desee informar a los consumidores que aún así la URI es correcta, que serán re-direccionados temporalmente a una URI con información de versión, pero que deberían seguir empleando la URI original.