Improve Your Web API with Swagger Documentation
Tags: api, swagger, tutorial, aspnetcore
Published: 2021-03-15 17:13:30

This post is one in a series of posts I am using to further enhance my development skillset. In this post, I will describe how to improve the Mural API [(my reference application used for educational purposes)](https://github.com/pdelcogliano) using Swagger documentation. Swagger is a set of tools based upon the OpenAPI Specification (OAS) which are used for documenting Web APIs. You may be wondering why documenting your API is necessary. Well, good documentation contributes to the overall user experience and is one of the biggest factors for increased API growth and usage. 

ASP.Net Core uses Swashbuckle, which is an open-source Swagger implementation used for generating API documentation. Through Swashbuckle you will generate living documentation every time you build your API, keeping the documentation in sync with the latest version of your API.

###Basic Swagger Documentation
The first thing we need to do is install Swashbuckle into the API project. Swashbuckle is available as a NuGet package. I am using PowerShell to install the NuGet package.
```powershell
Install-Package Swashbuckle.AspNetCore -Version 5.6.3
```
Swagger functionality is injected as middleware into the ASP.Net pipeline. Open the API project's Startup.cs file and edit the `ConfigureServices()` method. Add the line as shown below.
```c#
services.AddSwaggerGen(c =>
{
  c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mural", Version = "v1" });
});
```
While still editing the Startup.cs file, locate the `Configure()` method and enable middleware for the Swagger UI by adding `useSwagger` and `useSwaggerUI`.
```c#
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  app.UseSwagger();
  app.UseSwaggerUI(c =>
  {
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Mural V1");
  });
  /// rest of method body
```
Save the Startup.cs and run the project. Swashbuckle includes an implementation of the Swagger UI, which is a Web page that provides interaction and visualization to an API's resources. Navigate to the Swagger UI page by going to localhost:44333/swagger/index.html. Note, your local port may vary. When you open this page you will see the basic documentation that comes out of the box from Swagger.
![Basic Swagger Documentation](https://res.cloudinary.com/redfive/image/upload/v1615820191/Dev.to/swagger/MuralBasicSwagger_nwal2e.png)

Nice! With just a few lines of code and a NuGet package, we have a documented API. But, we can enhance the documentation with additional information, like examples for calling the API methods and descriptions of the method parameters. In the next section, we'll enrich the documentation to create an even better user experience.

###Providing Enhanced Documentation
We can enrich the API's documentation by including XML comments in the code. You place these comments directly before the code block about which you are commenting. The Swashbuckle tooling automatically includes XML comments in its documentation and makes them available to view via the Swagger UI Web page.

The first thing we need to do is to enable XML Comments in the project. XML comments can be enabled via several approaches. I chose to use the Project Properties Dialog as shown below. 

![Enable XML Comments via Project Properties Dialog](https://res.cloudinary.com/redfive/image/upload/v1615815434/Dev.to/swagger/MuralAPIProjectProperties_bsy5yj.png)

Using the dialog, navigate to the "Build" tab and click on the checkbox next to "XML Documentation file". Provide a name for the file, such as "M-url.Api.xml". Of note, when you enable XML Documentation, your code will generate warnings for any method that does not contain XML comments. If you want to disable this compiler warning, include `1591` in the Suppress warnings textbox.

Next, we need to add code to the Startup.cs file to inform Swagger where it can find the XML comments file. Replace the call to `AddSwaggerGen` we added earlier with the code shown below:
```c#
services.AddSwaggerGen(c =>
  {
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mural", Version = "v1" });

    // generate the XML docs that'll drive the swagger docs
    var xmlFile = $" 
      {Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    c.IncludeXmlComments(xmlPath);
  });
```
Now we'll add comments to the code. We'll start identifying which content-types the API handles on requests and responses. You use the `Produces` and `Consumes` attributes on the controller class to specify the content types allowed by the API. 
```c#
[Produces(MediaTypeNames.Application.Json, 
  MediaTypeNames.Application.Xml)]
[Consumes(MediaTypeNames.Application.Json, 
  MediaTypeNames.Application.Xml)]
public class SlugCollectionsController : ControllerBase
{ ... }
```
In the example above, the SlugsController accepts and returns both JSON and XML. This information will appear in the Swagger documentation.

Here I've added comments to the `GetSlugCollection()` method:
```c#
/// <summary>
/// Returns a collection of URLs
/// </summary>
/// <param name="slugs">list of slugs to retrieve</param>
/// <remarks>
/// Sample request:
///
///     Get /api/slugscollection/(d25tRx, fN5jpz)
///
/// </remarks>
/// <returns>IEnumerable of slugs</returns>
/// <response code="200">If all requested items are 
/// found</response>
/// <response code="400">If slugs parameter is missing</response>
/// <response code="404">If number of records found doesn't equal 
/// number of records requested</response>
[HttpGet("({slugs})", Name = "GetSlugCollection")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> GetSlugCollection([ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable<string> slugs)
{ ... }
```
While many of the comments are self-explanatory, I do want to highlight a few of them. The following table details the interaction between each XML comment attribute and its effect on the Swagger documentation.

| Comment Attribute | Swagger UI Action |
| ----------------- | ----------------- |
| summary | displays text next to the action method name |
| remarks | Supplements information specified in the <summary> element. Can consist of text, JSON, or XML|
| response | Renders as an example HTTP request in the Swagger documentation.|

Looking at the code snippet above, you'll notice the additional attribute, `ProducesResponseType` has been added to the method. ProducesResponseType informs Swagger of the HTTP Status codes returned by the method. The `response` XML comment works in conjunction with the ProducesResponseType attribute to provide descriptive information for each HTTP status code the method returns. 

Alternatively, in place of specifying each individual status code using ProducesResponseType, you can use the `ApiConventionMethod` attribute to specify 200, 400, and 404 status codes if your API produces a standard set of response codes. Here's an example:
```c#
[ApiConventionMethod(typeof(DefaultApiConventions))]
```
The final version of the GetSlugCollection method's documentation is below. You can see the additional descriptions next to the parameters, the HTTP status codes being returned, and an example of calling the API using a GET HTTP method.
![Enhanced Mural Documentation](https://res.cloudinary.com/redfive/image/upload/v1615824199/Dev.to/swagger/MuralEnhancedSwagger_uzasga.png)

There is one more change we can do to make the documentation complete. Back in the Startup.cs file, replace the call to AddSwaggerGen we modified earlier with the souped-up version shown below:
```c#
services.AddSwaggerGen(c =>
{
  c.SwaggerDoc("v1", new OpenApiInfo
  {
    Title = "Mural API",
    Description = "",
    Contact = new OpenApiContact
    {
      Name = "Paul Delcogliano",
      Email = "pdelco@gmail.com",
      Url = new Uri("https://github.com/pdelcogliano")
    },
    License = new OpenApiLicense
    {
      Name = "MIT License",
      Url = new Uri("https://opensource.org/licenses/MIT")
    }
  });

  // generate the XML docs that'll drive the swagger docs
  var xmlFile = $" 
    {Assembly.GetExecutingAssembly().GetName().Name}.xml";
  var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
  c.IncludeXmlComments(xmlPath);
});
```
In this version, we are using the `OpenApiInfo()` method to provide additional data for the document header. We are also using the `OpenApiLicense()` method to provide information about the API license. Here's the final Swagger documentation, shown in all of its glory with enhanced header information, and enriched method descriptions:

![Completed Mural API Documentation](https://res.cloudinary.com/redfive/image/upload/v1615825366/Dev.to/swagger/MuralFinalSwagger_iwa3r9.png)

Documenting an ASP.Net Core API using Swashbuckle and Swagger helps your API meet the goals of good documentation. Good documentation provides many benefits. It helps internal teams understand the API and agree on its attributes. It facilitates external clients' understanding of the API and the functionality it provides. More information about getting started with Swagger and Swashbuckle can be found [here](https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio).