Isaac.

web

API Documentation with Swagger

Generate interactive API documentation with Swagger/OpenAPI.

By Emem IsaacApril 1, 20213 min read
#swagger#openapi#api documentation#aspnet core
Share:

A Simple Analogy

Swagger is like a living user manual for your API. It documents endpoints, request/response formats, and you can test the API right from the documentation.


Why Swagger?

  • Self-documenting: Generate docs from code
  • Interactive: Test endpoints from browser
  • Standardized: OpenAPI specification
  • Client generation: Auto-generate SDKs
  • Contract: API contract for frontend/backend

Setup

// Program.cs
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        options.RoutePrefix = string.Empty;  // Show at root
    });
}

app.Run();

Endpoint Documentation

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    /// <summary>
    /// Get order by ID
    /// </summary>
    /// <param name="id">Order ID</param>
    /// <returns>Order details</returns>
    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderDto))]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<OrderDto>> GetOrder(int id)
    {
        var order = await _orderService.GetAsync(id);
        if (order == null) return NotFound();
        return Ok(order);
    }

    /// <summary>
    /// Create new order
    /// </summary>
    /// <remarks>
    /// Sample request:
    /// 
    ///     POST /api/orders
    ///     {
    ///         "customerId": "cust-123",
    ///         "items": [
    ///             {
    ///                 "productId": "p1",
    ///                 "quantity": 2,
    ///                 "price": 29.99
    ///             }
    ///         ]
    ///     }
    /// </remarks>
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(OrderDto))]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<OrderDto>> CreateOrder(CreateOrderRequest request)
    {
        if (!ModelState.IsValid) return BadRequest(ModelState);
        
        var order = await _orderService.CreateAsync(request);
        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }
}

Model Documentation

public class OrderDto
{
    /// <summary>
    /// Unique order identifier
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// Customer ID who placed the order
    /// </summary>
    [Required]
    public string CustomerId { get; set; }

    /// <summary>
    /// Order items
    /// </summary>
    [MinLength(1)]
    public List<OrderItemDto> Items { get; set; }

    /// <summary>
    /// Total order amount in USD
    /// </summary>
    [Range(0.01, double.MaxValue)]
    public decimal Total { get; set; }

    /// <summary>
    /// Order status (Pending, Confirmed, Shipped, Delivered, Cancelled)
    /// </summary>
    public OrderStatus Status { get; set; }
}

Advanced Configuration

builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "Order API",
        Version = "v1",
        Description = "API for managing orders",
        Contact = new OpenApiContact
        {
            Name = "Support",
            Email = "support@example.com"
        }
    });

    // Include XML comments
    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    options.IncludeXmlComments(xmlPath);

    // Add security definition
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

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

Custom Swagger UI

app.UseSwaggerUI(options =>
{
    options.DocumentTitle = "Order API Documentation";
    options.DefaultModelsExpandDepth(0);  // Don't expand schemas by default
    options.DefaultModelExpandDepth(2);   // But expand specific ones
    
    // Custom CSS
    options.InjectStylesheet("/swagger-ui.css");
    
    // Multiple API versions
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
    options.SwaggerEndpoint("/swagger/v2/swagger.json", "API V2");
});

Exclude from Documentation

[ApiExplorerSettings(IgnoreApi = true)]
[HttpPost("internal/process")]
public async Task<IActionResult> InternalProcess()
{
    // Not shown in Swagger
}

Best Practices

  1. Document thoroughly: Include examples
  2. Use response types: Specify all outcomes
  3. Validate inputs: Annotate constraints
  4. Version APIs: Support multiple versions
  5. Keep updated: Docs should match code

Related Concepts

  • API versioning strategies
  • OpenAPI code generation
  • API gateway documentation
  • GraphQL schema

Summary

Swagger transforms code documentation into interactive API references. Use XML comments and response type annotations to auto-generate comprehensive, testable documentation.

Share:

Written by Emem Isaac

Expert Software Engineer with 15+ years of experience building scalable enterprise applications. Specialized in ASP.NET Core, Azure, Docker, and modern web development. Passionate about sharing knowledge and helping developers grow.

Ready to Build Something Amazing?

Let's discuss your project and explore how my expertise can help you achieve your goals. Free consultation available.

💼 Trusted by 50+ companies worldwide | ⚡ Average response time: 24 hours