Cómo documentar tu API con Swagger (Swashbuckle)


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
Mantén la documentación actualizada: Los comentarios XML y atributos deben reflejar el comportamiento actual del código.
Usa ejemplos realistas: Proporciona ejemplos que realmente ayuden a entender el uso de la API.
Documenta casos de error: No olvides documentar qué códigos de error puede devolver cada endpoint.
Agrupa endpoints lógicamente: Usa controladores y tags para organizar la documentación.
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.
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.