ASP.NET Core 1.0: Web API Automatic Documentation with Swagger and Swashbuckle

Synopsis: In this article I will help you with getting automatically generated and interactive documentation going for your ASP.NET Core Web API by using Swagger and Swashbuckle. As of December 23rd upgraded to latest version. We’ll touch the following subjects:

  • Getting started
  • Multiple versions
  • Complex models
  • Adding XML notations
  • Multiple Responses

Want to read this in Dutch instead of English then click here. Small caveat, that article is not upgraded to the latest version!

Intro

The problem with any REST API is that you need to maintain the documentation describing the API manually (or even if you have it generated from code by some tool it’s still semi-automatic). So it will often be out of date, inaccurate, prone to mistakes and not interactive. To the rescue comes Swagger, which provides a powerful representation of your RESTful API, thus providing automatic documentation. Open sourced Swagger is platform-agnostic and this article is specifically about adding the power of Swagger to an ASP.NET Core Web API. In order to be able to do that I’d need an implementation specifically for this platform, which luckily is provided by the open source implementation called Swashbuckle 6.0.0.

Getting started

Swashbuckle seamlessly adds Swagger by combining the built in Api Explorer from ASP.NET Core MVC and Swagger’s swagger-ui to enable discovery and generate interactive documentation for your API’s users. Remember that at the time of writing it’s a release candidate and the interface might still shift and change in the future. But as for now the best way to get started is to install the NuGet packages called “Swashbuckle.SwaggerGen” and “Swashbuckle.SwaggerUi” both version “6.0.0-rc1-final”. There is only one NuGet package which contains the Swagger generator and Swagger-ui embedded. Add the package Swashbuckle 6.0.0-beta902 to the dependencies section of the project.json file:

    "Swashbuckle": "6.0.0-beta902"

Side note: They also have a meta-package called “Swashbuckle” which installs these two NuGet packages for you as well, but they are both older beta releases. Also, no sign of packages for RTM at the moment of writing this, but let’s hope the API doesn’t change.

Once this is done we’ll need to configure Swagger in the Startup class. First we’ll add the services needed in the ConfigureServices method of the StartUp class to generate the files Swagger needs, like this:

services.AddSwaggerGen();

This will register an implementation of ISwaggerProvider with the default settings. Then in the same class in the Configure method you need to add the middleware to the HTTP request pipeline like this:

app.UseSwagger();

This will serve the generated swagger as a JSON endpoint. If you would start up the web application now and you’d navigate to the standard route which is: “/swagger/v1/swagger.json”, you’d see the following JSON:

{"swagger":"2.0","info":{"version":"v1","title":"API V1"},"basePath":"/","paths":{},"definitions":{},"securityDefinitions":{}}

Side note: You can change this standard route as an option of the UseSwaggerGen extension method.

Well, let’s put Swagger to work by adding an MVC controller. Add the following code to the ConfigureServices method of the StartUp class:

services.AddMvc();

Add the following code to the Configure method of the StartUp class:

app.UseMvcWithDefaultRoute();

Add a folder named “Controllers”.

Add a class to this folder named “HomeController” and have it inherit from Controller. Add the following action method to the Home controller:

[HttpGet("About")]
public ContentResult About()
{
	return Content("An API to sample Swagger with Swashbuckle in ASP.NET Core.");
}

Now run the web application again and navigate to “/swagger/v1/swagger.json” and you should see the following JSON:

{"swagger":"2.0","info":{"version":"v1","title":"API V1"},"basePath":"/","paths":{"/About":{"get":{"tags":["Home"],"operationId":"AboutGet","produces":[],"responses":{"200":{"description":"OK"}},"deprecated":false}}},"definitions":{},"securityDefinitions":{}}

Notice how the key “paths” has an entry now, due to standard API discovery which Swashbuckle utilizes to generate the swagger.json to fuel the Swagger engine. To utilize swagger-ui and get interactive documentation you add the following line of code to the Configure method in the Startup class:

app.UseSwaggerUi();

This will add middleware to the HTTP request pipeline which will generate the interactive documentation based off of the swagger.json. So if you navigate to “swagger/ui” it will look like this:

figure1_swaggerui

Side note: UseSwaggerUI takes two parameters, “baseRoute” (to change the “swagger/ui” default route) and “swaggerURL” (to change the default location “/swagger/v1/swagger.json” where it expects the swagger.json file to be).

The interactive documentation is built up in a RESTful manner. So you first see the link “Home”, because the ‘resource’ “About” is beneath “Home”. If you’d click on it, you’d see the following:

figure2_swaggeruiWe can see it’s a “Get” method and we see the relative path “/About”. If you click on “/About” you’d see:

figure3_swaggerui

As you see it can list the response messages and you can also “Try it out!”. And if you’d click on that you’d see:

figure4_swaggerui

You can see the “CURL”, the “Request URL”, “Response Body”, “Response Code” and even the “Response Headers” with only three lines of code! Well, I think that is pretty sweet!

Multiple Versions

A common problem with API’s for external use is that you don’t know how many people are depending on your API and when you make a breaking change you don’t want to break everyone else’s code and you start versioning your API. Luckily Swagger has support for multiple versions and together with Swashbuckle you can easily configure it. Let’s start with making a second version of our “About” action method on the “Home” controller. Change the action methods as the code below:

[HttpGet("api/v1/About")]
public ContentResult About()
{
	return Content("An API to sample Swagger with Swashbuckle in ASP.NET Core.");
}

[HttpGet("api/v2/About")]
public ContentResult About2()
{
	return Content("An API (v2) to sample Swagger with Swashbuckle in ASP.NET Core.");
}

In the ConfigureServices method of the StartUp class add the following code:

services.AddSwaggerGen(options =>
	{
		options.MultipleApiVersions(new Swashbuckle.Swagger.Model.Info[]
		{
			new Swashbuckle.Swagger.Model.Info
			{
				Version = "v2",
				Title = "API (version 2.0)",
				Description = "A RESTful API to show Swagger and Swashbuckle"
			},
			new Swashbuckle.Swagger.Model.Info
			{
				Version = "v1",
				Title = "API",
				Description = "A RESTful API to show Swagger and Swashbuckle"
			}
		}, (description, version) =>
		{
			return description.RelativePath.Contains($"api/{version}");
		});

	});

Side note: If your Web API is hosted in IIS, you should avoid using full-stops in the version name (e.g. “1.0”). The full-stop at the tail of the URL will cause IIS to treat it as a static file (i.e. with an extension) and bypass the URL Routing Module and therefore, Web API.

The “ConfigureSwaggerDocument” “AddSwaggerGen” method is the extension method with which you’ll be able to configure your Swagger document. It takes an Action of SwaggerDocumentOptions SwaggerGenOptions, which has a “MultipleApiVersions” method which takes a collection of Info objects with which you can describe your versions. These are used purely for descriptive purposes.

The real workhorse is the second parameter which is a “Function” which takes an instance of “ApiDescription” and a “version” as a string and is expected to return a boolean, true if the specific version is hit, false if not. Because the solutions for this is not homogenised, Swashbuckle solved it like this and you can resolve the version anyway you like really, because of this clever mechanism. In this example I expect that in the route the version (e.g.: “v1” or “v2”) comes after “api/”.

If everything has been done correctly, you should be able to navigate to “swagger/ui” again and change “v2” in the URL to the swagger.json and press “Explore” to be able to try out version 2 of the About action method:

figure5_swaggerui

Complex Models

So that’s all fine and dandy, but what about more complex use cases where the action method expects an object and perhaps returns an object of some kind. Let me show you what that looks like with Swagger, by adding the following two class first:

public class Something
{
	[JsonProperty("someint")]
	public int SomeInt { get; set; }
	[JsonProperty("somestring")]
	public string SomeString { get; set; }
}

public class SomeResponse
{
	[JsonProperty("someresponseint")]
	public int SomeResponseInt { get; set; }
	[JsonProperty("someresponsestring")]
	public string SomeResponseString { get; set; }
}

Then add the following action method to HomeController:

[HttpPost("api/v1/GiveMeSomething")]
public IActionResult GiveMeSomething([FromBody] Something something)
{
	return Ok(new SomeResponse()
	{
		SomeResponseInt = something.SomeInt,
		SomeResponseString = something.SomeString
	});
}

Navigate to “swagger/ui” again. Notice how “GiveMeSomething” is added. Notice how it discovered that it needs a parameter called “something”. See the “Model Schema” on the right, click on it to add it as a value of parameter “something”. Change the individual values and click “Try it out!” and it should look like:

figure6_swaggerui

Side note: Notice how Swagger uses the JSON names that are declared above the properties.

Adding XML notations

So far the generated documentation hasn’t been very descriptive. Luckily Swashbuckle can utilize XML comments to add documentation to Swagger. First we’ll need to check the “produce outputs on build” “XML documentation file” (VS2015 update 3) checkbox on the “Build” tab of the project properties (or set xmlDoc to true in the buildOptions section in the project.json file):

figure7_produceoutputsonbuild

This will produce the file with the XML comments in it, which Swashbuckle needs to be able to utilize them. Now adjust your code as follows:

services.AddSwaggerGen(options =>
	{
		options.MultipleApiVersions(new Swashbuckle.Swagger.Model.Info[]
		{
			new Swashbuckle.Swagger.Model.Info
			{
				Version = "v2",
				Title = "API (version 2.0)",
				Description = "A RESTful API to show Swagger and Swashbuckle"
			},
			new Swashbuckle.Swagger.Model.Info
			{
				Version = "v1",
				Title = "API",
				Description = "A RESTful API to show Swagger and Swashbuckle"
			}
		}, (description, version) =>
		{
			return description.RelativePath.Contains($"api/{version}");
		});
		options.IncludeXmlComments(pathToDoc);
	});

Side note: The variable pathToDoc is the path to the XML documentation file. Adjust this to your own personal needs.

Now we can add some XML comments to the controller and models:

/// <summary>
/// Default entrypoint of the API.
/// </summary>
public class HomeController: Controller
{
	/// <summary>
	/// Description of what this API is about.
	/// </summary>
	/// <returns></returns>
	[HttpGet("api/v1/About")]
	public ContentResult About()
	{
		return Content("An API to sample Swagger with Swashbuckle in ASP.NET Core.");
	}

	/// <summary>
	/// Give something and it will return a response.
	/// </summary>
	/// <param name="something"></param>
	/// <returns></returns>
	[HttpPost("api/v1/GiveMeSomething")]
	public IActionResult GiveMeSomething([FromBody] Something something)
	{
		return Ok(new SomeResponse()
		{
			SomeResponseInt = something.SomeInt,
			SomeResponseString = something.SomeString
		});
	}

	/// <summary>
	/// Description of what API v2 is about.
	/// </summary>
	/// <returns></returns>
	[HttpGet("api/v2/About")]
	public ContentResult About2()
	{
		return Content("An API (v2) to sample Swagger with Swashbuckle in ASP.NET Core.");
	}
}

/// <summary>
/// Just something to put in the request.
/// </summary>
public class Something
{
	/// <summary>
	/// Just some int.
	/// </summary>
	[JsonProperty("someint")]
	public int SomeInt { get; set; }
	/// <summary>
	/// Just some string.
	/// </summary>
	[JsonProperty("somestring")]
	public string SomeString { get; set; }
}

/// <summary>
/// Just some response to give back.
/// </summary>
public class SomeResponse
{
	/// <summary>
	/// Some int for the response.
	/// </summary>
	[JsonProperty("someresponseint")]
	public int SomeResponseInt { get; set; }
	/// <summary>
	/// Some string for the response.
	/// </summary>
	[JsonProperty("someresponsestring")]
	public string SomeResponseString { get; set; }
}

And if you’d navigate again to “swagger/ui” you should see something like:

figure8_xmlcomments

Please note that “Model” is clicked instead of “Model Schema” beneath “Data Type” to make the XML comments visible on the model. Furthermore, note the XML comments visible behind the relative URL’s.

We are almost done with the basics, but before I end this article we should really look at the response, which is still at its bare minimum right now.

Multiple Responses

What if we’d adjust the “GiveMeSomething” method to check if “SomeInt” is below 50 and return a BadRequest if it isn’t, as follows:

/// <summary>
/// Give something and it will return a response.
/// </summary>
/// <param name="something"></param>
/// <returns></returns>
[ProducesResponseType(typeof(SomeResponse), 200)]
[ProducesResponseType(typeof(BadRequestResultObject), 400)]
[HttpPost("api/v1/GiveMeSomething")]
public IActionResult GiveMeSomething([FromBody] Something something)
{
	if (something.SomeInt <= 50)
	{
		return Ok(new SomeResponse()
		{
			SomeResponseInt = something.SomeInt,
			SomeResponseString = something.SomeString
		});
	}
	else
	{
		return new BadRequestObjectResult(new SomeResponse()
		{
			SomeResponseInt = 0,
			SomeResponseString = string.Empty
		});
	}
}

Now it returns two responses, an OK status and a BadRequest. For Swashbuckle to be able to utilize this in the documentation you need to add the SwaggerResponse ProducesResponseType attribute. It’ll take a status code it’s triggered on, and a type of the response. If you provide a type it’ll enable Swashbuckle to utilize the XML comments on the model again. So if you’d navigate to “swagger/ui” again it should look like:

figure9_multipleresponses
Side noteImage may not be entirely accurate anymore.

You see the main response, in this case “Response Class (Status 200), right beneath the relative URL “/api/v1/GiveMeSomething”. As you can see the XML comments are visible for “someresponseint” and “someresponsestring”. And beneath the “Parameters” section you see the “Response Messages” section which will list all the other responses. In this case it shows us we can expect a HTTP Status Code of 400 and the description is shown under “Reason” and the XML comments are shown again at “Response Model”.

Outro

These are the basic features of Swagger with Swashbuckle on ASP.NET Core which should give you a flying start! If you feel anything is missing, or you have any questions let me know in the comment section. As for now, I hope this helped you getting started!

Advertisements

About Danny

Bachelor in Commercial ICT MCTS Winforms .NET 2.0 MCTS ASP.NET 3.5 PSM I
This entry was posted in .NET programming, ASP.NET Core 1.0 and tagged , , . Bookmark the permalink.

9 Responses to ASP.NET Core 1.0: Web API Automatic Documentation with Swagger and Swashbuckle

  1. Morten Haahr says:

    Could you provide a link for the source code?

  2. Victor Hugo Silva says:

    When using MultipleApiVersions option with a composed route, like “api/v{version:apiVersion}/[controller]”, the RelativePath property shows up “api/v{version}/ControllerName”. This way it is impossible to determine which version should be applied. Is there any workaround?
    Thx in advance!

    • Danny says:

      Unfortunately I don’t think it’s possible. The swagger.json is generated through discovery on the api. The version in your routes are resolved at runtime. May I ask why you solved it like this?

  3. Quang says:

    hi Danny,
    Do you know how to get custom values from code into the tags? Both at the API and the method level. Swashbuckle seems to have some default behaviour around how it comes up with method level tags but nothing at the API level.

    • Danny says:

      Hey Quang, I am having trouble understanding your question. Could you provide a small code sample with what you mean by the difference of API level and method level?

  4. Quang says:

    hi Danny,
    Thanks for your response. I worked this out, I needed use of GroupActionsBy and DocumentFilter allows me to set tags at the API and Controller level (I called this method in my prev post).

  5. jholovacs says:

    Are there any alternatives to swagger/ swashbuckle? I much prefer the older version of web api documentation, much easier to maintain, and the UI was not nearly as heavy.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s