Documentando tu API versionada con Swagger
Tags: csharp, aspnetcore, dotnet, programming
Published: 2021-02-02 11:54:02

En el [post anterior](https://dev.to/adevintaspain/versionando-tu-api-en-net-core-9c4) vimos lo importante que es versionar nuestra API en .NET Core. En este post veremos como mostrar la documentación de esta API de manera visual usando Swagger.

##Documentando tu API sin versionado

Si queremos documentar una API sin versionado debemos seguir los siguientes pasos:

1- Clonar el repositorio con la API versionada de la cual hablamos en el [post anterior](https://dev.to/adevintaspain/versionando-tu-api-en-net-core-9c4)

```powershell
git clone https://github.com/jhonmarmolejo/NetCoreApiVersionDemo.git
```


2- Abrir la solución y añadir los siguientes nugets al proyecto que contiene la API

```powershell
Install-Package Swashbuckle.AspNetCore.SwaggerGen -Version 5.6.3
Install-Package Swashbuckle.AspNetCore.SwaggerUI -Version 5.6.3
```


3- Añadimos una nueva clase para extender la configuración de la API con la configuración de Swagger. A esta clase la llamaremos **OpenApiConfiguration.cs**

```csharp
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

namespace MyApi.Extensions
{
    internal static class OpenApiConfiguration
    {
        public static IServiceCollection AddCustomOpenApi(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API Swagger", Version = "v1" });
                c.IncludeXmlComments(Path.Combine(System.AppContext.BaseDirectory, "MyApi.xml"),true);
                c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
            });

            return services;
        }

        public static void UseCustomSwagger(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API Swagger"); });
        }
    }
}
```
Donde en el método **AddCustomApi** configuramos lo siguiente:

 - El título y la versión de Open Api para la documentación.

```csharp
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API Swagger", Version = "v1" });
```
 - El path que usará Swagger para generar la documentación

```csharp
c.IncludeXmlComments(Path.Combine(System.AppContext.BaseDirectory, "MyApi.xml"),true);
```

> NOTA: El path que usaremos aqui es del archivo de documentación que genera la API, para esto debemos ir a las propiedades de la API y marcar el check de XML Documentation file 

>![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s38hx4aotz02dtnlvx4m.png)

- Ya que nuestra API de ejemplo es versionada, tenemos que añadir este método para que Swagger resuelva conflictos en el caso de que encuentre endpoints duplicados.

```csharp
 c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
```

Y el método **UseCustomSwagger** nos permite indicar que usaremos la parte visual de Swagger.


4- En **Startup.cs**, llamamos a `services.AddCustomOpenApi();` en el método 
   ConfigureServices
```csharp
  public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddCustomOpenApi();
            ...
            ...
            ...
        }
```

Y llamamos a `app.UseCustomSwagger` en el método Configure 
```csharp
 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCustomSwagger();
            ...
            ...
            ...
        }
```

5- Ahora sólo queda ejecutar tu API e ir a la url /swagger/index.html

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7u2ect1ofr35ir1jthuk.JPG)


## Documentando tu API con versionado

En el caso de que quedaremos documentar nuestra API versionada con Swagger, debemos hacer lo siguiente:

1. Seguir todos los pasos explicados anteriormente.
2. Añadir los siguientes filtros

**SwaggerRemoveVersionFilter.cs** -> quita el parámetro `version` de la operación


```csharp
using System.Linq;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace MyApi.Filters
{
    public class SwaggerRemoveVersionFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var versionParameter = operation.Parameters.FirstOrDefault(p => p.Name == "version");

            if (versionParameter != null)
            {
                operation.Parameters.Remove(versionParameter);
            }

        }
    }
}
```

**SwaggerReplaceVersionFilter** -> modifica el path que usará Swagger de acuerdo a la versión 

```csharp
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace MyApi.Filters
{
    public class SwaggerReplaceVersionFilter : IDocumentFilter
    {
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var paths = swaggerDoc.Paths;
            swaggerDoc.Paths = new OpenApiPaths();

            foreach (var path in paths)
            {
                var key = path.Key.Replace("v{version}", swaggerDoc.Info.Version);
                var value = path.Value;
                swaggerDoc.Paths.Add(key, value);
            }
        }
    }
}
```
3- En la clase **OpenApiConfiguration.cs**, modificar el método **AddCustomOpenApi** para llamar a los nuevos filtros al final.

```csharp
public static IServiceCollection AddCustomOpenApi(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API Swagger v1", Version = "v1" });
                c.SwaggerDoc("v2", new OpenApiInfo { Title = "My API Swagger v2" , Version = "v2" });

                c.IncludeXmlComments(Path.Combine(System.AppContext.BaseDirectory, "MyApi.xml"),true);
                
                c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                c.OperationFilter<SwaggerRemoveVersionFilter>();
                c.DocumentFilter<SwaggerReplaceVersionFilter>();
            });

            return services;
        }
```

4- En la clase **Startup.css**, modificamos la configuración de OpenApi para usar el versionado por URL, esto lo hacemos para poder lanzar los ejemplos desde la misma interfaz que genera Swagger. 

```csharp
     services.AddApiVersioning(x =>
            {
                x.DefaultApiVersion = new ApiVersion(1, 0);
                x.AssumeDefaultVersionWhenUnspecified = true;
                x.ReportApiVersions = true;
            });
```

5- Por último vamos a los controllers y añadimos la siguiente cabecera en el inicio de la clase para indicar que usaremos el versionado por url

```csharp
 [Route("api/v{version:apiVersion}/[controller]")]
 public class DemoController : ControllerBase
 {
    ...
    ...
    ...
 }
```

6- Ahora sólo queda ejecutar tu API e ir a la url /swagger/index.html donde podemos ver las diferentes versiones de la API

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/trz4d2qwd3akxtmjbi7i.png)

Y podemos lanzar las ejecuciones desde aquí validando que las respuestas son de las versiones que hemos seleccionado

**Ejecutando la version 1 de la API**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/iizn78i8hyvop52o9myz.png)

**Ejecutando la version 2 de la API**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x7vx933nfoilcr4b2jxi.png)


El código de la API versionada con Swagger lo puedes encontrar en la rama **feature/ApiWithSwagger** en el siguiente repositorio

https://github.com/jhonmarmolejo/NetCoreApiVersionDemo/tree/feature/ApiWithSwagger


Hasta la próxima!!