En el post anterior 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
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
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
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.
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API Swagger", Version = "v1" });
- El path que usará Swagger para generar la documentación
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
- 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.
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
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCustomOpenApi();
...
...
...
}
Y llamamos a app.UseCustomSwagger
en el método Configure
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
Documentando tu API con versionado
En el caso de que quedaremos documentar nuestra API versionada con Swagger, debemos hacer lo siguiente:
- Seguir todos los pasos explicados anteriormente.
- Añadir los siguientes filtros
SwaggerRemoveVersionFilter.cs -> quita el parámetro version
de la operación
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
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.
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.
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
[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
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
Ejecutando la version 2 de la API
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!!