¿Cómo versionar APIs en .Net Core?

Estamos en un mundo dominado por los dispositivos móviles,. La sociedad ha evolucionado en los últimos años y cada vez hay más personas que utilizan sus smartphones o tablets para comunicarse, consumir contenidos, realizar compras, gestiones, etc.
En este escenario, las empresas están obligadas a abrir y mantener nuevos canales de comunicación y negocios adaptados a esta nueva situación.

Desde el punto de vista del software, esto implica desarrollar sistemas que deben funcionar incluso sin tener el control del último eslabón de la cadena: El dispositivo del consumidor.

La rápida evolución y entrega de valor de esas aplicaciones móviles obligan a realizar el mismo esfuerzo con las APIs que les dan soporte, pero no nos podemos olvidar de la compatibilidad, puesto que hay usuarios que no pueden, no desean, o simplemente no se preocupan de mantener actualizadas sus aplicaciones. Si una API evoluciona sin tener en cuenta a este segmento de usuarios, probablemente sus aplicaciones dejen de funcionar correctamente, lo que impactaría en primer lugar en la experiencia de usuario, y finalmente, en el negocio empresarial.

Por todo esto, siempre que se desarrolle una API, se debe utilizar una herramienta que nos ayuda a mantener esa retro compatibilidad: El versiondo de API.

El versionado nos permite definir a nivel de controlador y action cuales son las versiones de API soportadas. De esta forma, una determinada versión de una aplicación móvil utilizará siempre una determinada versión de la API, lo que permitirá que siga funcionando aunque la API continue su evolución.

Tipos de versionado

Existen distintos tipos de versionado:

Versionado por MediaType: Consiste en enviar la versión utilizando el header Accept. Ejemplo:

Accept: application/json;v=1.0

Versionado por custom headers: Consiste en utilizar headers personalizados. Ejemplo:

API-Version: 1.0

Versionado por URL: Consiste en incluir el número de versión en la Url del recurso. Ejemplo:

https://my-api.com/v1/customers

Todos los tipos de versionado son igualmente válidos, pero bajo mi punto de vista el menos recomendable es utilizar el versionado por Url, puesto que la dirección del recurso no debería cambiar. El uso de los MediaType y los Custom Headers es muy cómodo a la hora de realizar las peticiones a la API.

Ejemplo de implementación en .Net Core

En el siguiente ejemplo se muestra la implementación del código necesario para habilitar el versionado de API utilizando los MediaType.

En primer lugar, debemos instalar el paquete NuGet correspondiente:

Microsoft.AspNetCore.Mvc.Versioning

Posteriormente, debemos incluir el versionado dentro del método ConfigureServices de nuestra clase Startup.cs

services.AddApiVersioning(o =>
{
   o.ReportApiVersions = true;
   o.AssumeDefaultVersionWhenUnspecified = true;
   o.ApiVersionReader = new MediaTypeApiVersionReader();
   o.DefaultApiVersion = new ApiVersion(1, 0);
});

En este caso, estamos indicando que:

  •  Vamos a utilizar versionado
  •  En caso de no especificar la versión, se utilizará la versión por defecto
  • El tipo de versionado es utilizando los MediaType
  • La versión por defecto es 1.0

Por último, debemos decorar los controladores y actions con sus correspondientes atributos de versiones. Tanto los controladores como sus actions pueden dar soporte a más de una versión. No es necesario definir la versión a nivel de action si coincide con las versiones soportadas por su controlador.

[ApiController]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
   [HttpGet]
   [MapToApiVersion(“1.0”)]
   [Produces(“application/json”)]
   public ActionResult TestV1_0()
   {
      return base.Ok(“Ok v1.0”);
   }

   [HttpGet]
   [MapToApiVersion(“1.1”)]
   [Produces(“application/json”)]
   public ActionResult TestV1_1()
   {
      return Ok(“Ok v1.1”);
   }
}

En este ejemplo, nuestro controlador soporta las versiones 1.0 y 1.1, pero dentro existen dos actions, cada uno correspondiente a una única versión.

Estos métodos se consumen a través de una llamada GET, incluyendo el header accept:

curl -X GET «https://my-api.com/api/values” -H «accept: application/json;v=1.1»

Nota importante:

Debe utilizarse el Header accept para solicitar una versión concreta para las peticiones en las que no se envía contenido al servidor: GET, DELETE, HEAD y OPTIONS

Debe utilizarse el header Content-Type para solicitar una versión concreta en las peticiones en las que se envía contenido al servidor, típicamente: POST, PUT y PATCH

Escrito por: Daniel Asensio, Technical Lead de BackEnd en Bravent.