BlogController vs. Minimal: Tailoring Swagger Integration in .NET APIs
Nov 26, 2023 · Luka Zlatecan

Controller vs. Minimal: Tailoring Swagger Integration in .NET APIs

Two ways to add Swagger/OpenAPI documentation to .NET APIs — controller-based vs. minimal APIs — and when to use each.

Controller based vs minimal api open api swagger

In the digital age, the effectiveness of an API is as crucial as its functionality, making clear and comprehensive documentation a necessity. This is where Swagger, a leading tool in API documentation, comes into play, particularly within the .NET ecosystem. It offers two distinct approaches for API development: the traditional controller-based model and the minimal API model. Each presents unique opportunities for integrating Swagger, a key to unlocking interactive and user-friendly API documentation.

In this blog, we'll dive into the integration of Swagger in both controller-based and minimal APIs in .NET, exploring their differences, advantages, and challenges.

What is Swagger?

Swagger is a widely used set of tools for implementing the OpenAPI Specification (OAS). It provides a powerful yet user-friendly way to document, design, build, and test APIs. Initially developed as an independent project, Swagger has evolved to become synonymous with API documentation and design.

The OpenAPI Specification, formerly known as the Swagger Specification, is an API description format for REST APIs. It offers a standard, language-agnostic interface which allows both humans and computers to understand the capabilities of a service without accessing its source code. While Swagger and OpenAPI are often used interchangeably, they are not exactly the same: Swagger refers to the suite of tools around the OpenAPI Specification, whereas OpenAPI is the specification itself.

Differentiating Between Controller-Based and Minimal APIs

Controller-Based APIs

Controller-based APIs in .NET implement the controller part of the traditional MVC (Model-View-Controller) pattern. They provide a structured approach to API development, where each controller class handles requests for a specific route or resource.

```csharp
[ApiController]
[Route("[controller]")]
public class CarController : ControllerBase
{
[HttpGet]
public ActionResult<List<Car>> GetAll()
{
// Implementation to return car data
}
}
```

Minimal APIs

Introduced in .NET 6, minimal APIs are a leaner way to create web APIs with fewer files and less boilerplate code. They are ideal for microservices and small-scale applications.

```csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("MinimalApi/Car", () => {
// Implementation to return car data
});

app.Run();
```

Key Differences

  1. Structure: Controller-based APIs use a class-based structure, whereas minimal APIs are more route-focused with a functional style.
  2. Boilerplate Code: Controller-based APIs require more boilerplate; minimal APIs are succinct.
  3. Flexibility vs. Simplicity: Controller-based APIs offer more flexibility and features out of the box; minimal APIs opt for simplicity.

Controller-based APIs are well-suited for large-scale applications and offer built-in features like model validation, dependency injection, and attribute routing, at the cost of more boilerplate. Minimal APIs are ideal for microservices and small applications with a quicker setup, but ship with less functionality out-of-the-box.

Setting Up Swagger in Controller-Based APIs

Step 1: Install Swagger Dependencies

```xml
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
```

Step 2: Configure Swagger in Program.cs

```csharp
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "OpenApi Demo - Controller",
Description = "A web api showcasing how to create a good open api specification in a controller-based project.",
});

List<string> xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml", SearchOption.TopDirectoryOnly).ToList();
xmlFiles.ForEach(xmlFile => options.IncludeXmlComments(xmlFile));
});
```

Remember to include the GenerateDocumentationFile XML tag in your .csproj file so that Swagger can pick up your code comments:

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

Then enable the Swagger middleware:

```csharp
app.UseSwagger();
app.UseSwaggerUI();
```

Step 3: Annotate Your API

```csharp
/// <summary>
/// Get all cars.
/// </summary>
/// <remarks>All cars are good.</remarks>
/// <returns>A list of Cars.</returns>
/// <response code="200">All cars.</response>
[HttpGet(Name = "GetAllCars")]
[ProducesResponseType(typeof(List<Car>), StatusCodes.Status200OK)]
public ActionResult<List<Car>> GetAll()
{
return Ok(_carRepository.GetAll());
}
```

Once everything is set up, run your application and navigate to https://localhost:<port>/swagger to see the Swagger UI.

Setting Up Swagger in Minimal APIs

The initial steps mirror the controller-based setup — add the Swagger packages and configure the services in Program.cs. The key difference lies in how endpoints are defined and documented. There are three distinct ways:

1. Fluent API

```csharp
app.MapGet("MinimalApiFluent/Car", GetAll)
.WithName("MinimalFluentGetAllCars")
.WithSummary("Get all cars.")
.WithDescription("All cars are good.")
.Produces<List<Car>>()
.WithOpenApi();
```

2. Operation Model

```csharp
group.MapGet("/", GetAll)
.WithOpenApi(operation =>
{
operation.OperationId = "MinimalOperationGetAllCars";
operation.Summary = "Get all cars.";
operation.Description = "All cars are good.";
return operation;
});
```

3. XML Comments

```csharp
app.MapGet("MinimalApiXml/Car", GetAll);
/// <summary>
/// Get all cars.
/// </summary>
/// <remarks>All cars are good.</remarks>
/// <returns>A list of Cars.</returns>
/// <response code="200">All cars.</response>
private Ok<List<Car>> GetAll()
{
return TypedResults.Ok(_carRepository.GetAll());
}
```

Conclusion

The choice of approach for incorporating Swagger should be in harmony with your application's scale and intricacy:

  • Controller-Based API Integration shines in larger-scale applications where a structured design and comprehensive documentation are paramount.
  • Minimal API Integration is more suitable for smaller projects where simplicity and rapid setup are the main objectives.

Irrespective of the selected strategy, the crux lies in striking a balance between the specific demands of your project and the inherent strengths of each approach.

A practical example demonstrating both approaches is available on GitHub at https://github.com/indigolabsslo/IndigoLabs.OpenApi, and Microsoft's official guidance is at https://aka.ms/aspnetcore/swashbuckle.