Cómo documentar tu API con Swagger (Swashbuckle)

Iván PeinadoIván Peinado
5 min read

La documentación de APIs es uno de esos aspectos que muchos desarrolladores tendemos a posponer hasta el último momento. Sin embargo, una buena documentación puede marcar la diferencia entre una API exitosa y una que nadie quiere usar. En este artículo te mostraré cómo implementar Swagger en tu proyecto .NET usando Swashbuckle de forma práctica y profesional.

📝 ¿Qué es Swagger y por qué usarlo?

Swagger es una especificación para documentar APIs REST que permite generar documentación interactiva automáticamente. Con Swagger, los desarrolladores pueden:

  • Explorar endpoints de forma visual
  • Probar requests directamente desde el navegador
  • Generar código cliente automáticamente
  • Mantener documentación actualizada con el código

Swashbuckle es la implementación de Swagger para .NET que se integra perfectamente con ASP.NET Core.

🔧 Instalación y configuración básica

Paso 1: Instalar el paquete NuGet

dotnet add package Swashbuckle.AspNetCore

Paso 2: Configurar servicios en Program.cs

var builder = WebApplication.CreateBuilder(args);

// Agregar servicios
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configurar pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Con esta configuración básica ya tendrás Swagger funcionando en /swagger cuando ejecutes tu aplicación en modo desarrollo.

📋 Documentando endpoints con atributos

Información básica del endpoint

[HttpGet]
[Route("api/users")]
[ProducesResponseType(typeof(List<User>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<List<User>>> GetUsers()
{
    // Lógica del endpoint
}

Documentación detallada con Summary y Remarks

/// <summary>
/// Obtiene un usuario específico por su ID
/// </summary>
/// <param name="id">Identificador único del usuario</param>
/// <returns>Los datos del usuario solicitado</returns>
/// <remarks>
/// Ejemplo de uso:
/// 
///     GET /api/users/123
///     
/// </remarks>
[HttpGet("{id}")]
[ProducesResponseType(typeof(User), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<User>> GetUser(int id)
{
    // Lógica del endpoint
}

⚙️ Configuración avanzada

Información general de la API

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "Mi API",
        Version = "v1",
        Description = "Una API para gestionar usuarios y productos",
        Contact = new OpenApiContact
        {
            Name = "Tu Nombre",
            Email = "tu@email.com",
            Url = new Uri("https://tuwebsite.com")
        },
        License = new OpenApiLicense
        {
            Name = "MIT",
            Url = new Uri("https://opensource.org/licenses/MIT")
        }
    });
});

Incluir comentarios XML

Primero, habilita la generación de comentarios XML en tu archivo .csproj:

<PropertyGroup>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Luego configura Swagger para usar estos comentarios:

builder.Services.AddSwaggerGen(c =>
{
    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    c.IncludeXmlComments(xmlPath);
});

🔐 Documentando autenticación

JWT Bearer Token

builder.Services.AddSwaggerGen(c =>
{
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header usando el esquema Bearer. Ejemplo: 'Bearer {token}'",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] {}
        }
    });
});

Documentar endpoints protegidos

[HttpPost]
[Authorize]
[ProducesResponseType(typeof(User), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<User>> CreateUser(CreateUserDto userDto)
{
    // Lógica del endpoint
}

🎨 Personalización de la interfaz

Configuración de SwaggerUI

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mi API V1");
        c.RoutePrefix = string.Empty; // Swagger en la raíz
        c.DocumentTitle = "Mi API - Documentación";
        c.DefaultModelsExpandDepth(-1); // Ocultar modelos por defecto
        c.DisplayRequestDuration();
    });
}

Múltiples versiones de API

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mi API", Version = "v1" });
    c.SwaggerDoc("v2", new OpenApiInfo { Title = "Mi API", Version = "v2" });
});

// En el middleware
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mi API V1");
    c.SwaggerEndpoint("/swagger/v2/swagger.json", "Mi API V2");
});

📊 Ejemplos y esquemas personalizados

Usar atributos para ejemplos

public class CreateUserDto
{
    /// <summary>
    /// Nombre del usuario
    /// </summary>
    /// <example>Juan Pérez</example>
    [Required]
    public string Name { get; set; }

    /// <summary>
    /// Email del usuario
    /// </summary>
    /// <example>juan@ejemplo.com</example>
    [Required]
    [EmailAddress]
    public string Email { get; set; }
}

Filtros personalizados

public class SwaggerExampleFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.RequestBody?.Content != null)
        {
            foreach (var mediaType in operation.RequestBody.Content.Values)
            {
                mediaType.Example = new OpenApiString("Ejemplo personalizado");
            }
        }
    }
}

// Registrar el filtro
builder.Services.AddSwaggerGen(c =>
{
    c.OperationFilter<SwaggerExampleFilter>();
});

🌍 Configuración para producción

Habilitación condicional

var app = builder.Build();

// Solo en desarrollo o con configuración específica
if (app.Environment.IsDevelopment() || 
    app.Configuration.GetValue<bool>("EnableSwagger"))
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

Configuración de CORS para Swagger

builder.Services.AddCors(options =>
{
    options.AddPolicy("SwaggerPolicy", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader();
    });
});

// Usar CORS antes de Swagger
app.UseCors("SwaggerPolicy");
app.UseSwagger();
app.UseSwaggerUI();

🔧 Troubleshooting común

Problema: Swagger no muestra todos los endpoints

Solución: Verificar que los controladores estén registrados correctamente:

builder.Services.AddControllers();
app.MapControllers();

Problema: Comentarios XML no aparecen

Solución: Verificar la ruta del archivo XML:

var xmlPath = Path.Combine(AppContext.BaseDirectory, "MiProyecto.xml");
if (File.Exists(xmlPath))
{
    c.IncludeXmlComments(xmlPath);
}

Problema: Errores de serialización en modelos complejos

Solución: Configurar el serializador JSON:

builder.Services.Configure<JsonOptions>(options =>
{
    options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});

🚀 Mejores prácticas

  1. Mantén la documentación actualizada: Los comentarios XML y atributos deben reflejar el comportamiento actual del código.

  2. Usa ejemplos realistas: Proporciona ejemplos que realmente ayuden a entender el uso de la API.

  3. Documenta casos de error: No olvides documentar qué códigos de error puede devolver cada endpoint.

  4. Agrupa endpoints lógicamente: Usa controladores y tags para organizar la documentación.

  5. Valida la documentación: Prueba regularmente que la documentación generada sea precisa y útil.

📚 Conclusión

Implementar Swagger con Swashbuckle en tu proyecto .NET es una inversión que vale la pena. No solo mejora la experiencia de los desarrolladores que consumen tu API, sino que también facilita el mantenimiento y la evolución del proyecto.

La documentación automática elimina la carga de mantener documentación separada, garantizando que siempre esté sincronizada con el código. Con las técnicas mostradas en este artículo, puedes crear una documentación profesional y completa que hará que tu API destaque.


¿Te ha resultado útil esta guía? Comparte tus experiencias documentando APIs en los comentarios.

0
Subscribe to my newsletter

Read articles from Iván Peinado directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Iván Peinado
Iván Peinado

20 años de experiencia como desarrollador en tecnologías .NET. Desde que comencé mi aventura profesional no he dejado de interesarme por todo lo que rodea a esta tecnología. Me considero un apasionado de mi trabajo, intentando siempre aprender, evolucionar y conseguir unas metas y objetivos. La tecnología cambia constantemente y por ello es necesario tener una base consolidada y seguir adquiriendo nuevos y mayores conocimientos que hagan de nuestro trabajo más fácil. Intento siempre, aprender nuevas herramientas y funcionalidades relacionadas con la tecnología .NET que me ayude a seguir avanzando en mi carrera profesional y aportando nuevas ideas en los proyectos en los que participo.