Give your Web API some Swagger with Swashbuckle

PUBLISHED ON OCT 15, 2016 ‚ÄĒ .NET, .NET CORE, RESTFUL

At work I’m currently working on my very first Web API using .NET Core. As part of this, we wanted to set it up to follow the OpenAPI specification, and provide a tool for other developers here to quickly find out more about the API and test some basic use cases.

Swagger seemed like a good answer to all this, and fortunately there’s even a ready to go implementation for .NET called Swashbuckle. In this post I’ll cover the basics to get up and running with Swashbuckle on a Web API.

I’m going to use a new, default Web API project for this, but it’s easy enough to add this to your existing work, as you’ll see.

First, we need to add Swashbuckle to our project. Open the nuget package manager, ensure you’re including pre-release packages, and find Swashbuckle. At the time of writing this, the latest stable version of Swashbuckle doesn’t support .NET Core, and so you’ll need the latest pre-release version until this goes live. At writing, the latest version is v6.0.0-beta902.

One of the good things about Swashbuckle is that it’s open source, you can find the new repo here. They’ve started from scratch to support .NET Core, so if you do encounter any issues, you can get involved and help resolve the issues yourself ūüôā

Now that we have Swashbuckle, it needs to be configured so we can actually make use of it. To do this, go to Startup.cs, and in your ConfigureServices method add:

services.AddSwaggerGen();

and in your Configure method add the following:

app.UseSwagger();
app.UseSwaggerUi();

And that’s it.

If you now run the project, and go to /swagger/ui, you’ll see the name of your controller(s), I see Values. Clicking on that expands out a list of all the endpoints available, nicely colour coded based on what they do!

Initial setup of Swagger

So let’s customize it a bit. First, it would be good to give some more detail to anyone viewing your API.

We’ll add some basic details of the API, and who to contact. To do this, go back to your ConfigureServices method in Startup.cs, and add a call to ConfigureSwaggerGen on the services. In here, we want to create a new SingleApiVersion on the options, setting the desired values:

services.ConfigureSwaggerGen(options =>
    {
        options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info
            {
                Version = "v1",
                Title = "Swashbuckle Example API",
                Description = "What did you expect? It's just for a blog post!",
                Contact = new Swashbuckle.Swagger.Model.Contact() {
                    Email = "ian@iamrufio.com",
                    Name = "Ian",
                    Url = "iamrufio.com"
                }
            });
    });

As you can see, I’ve set a version, a title of the API and it’s description, as well as my contact details so people can shout at me for anything stupid I’ve done.

If you run it again and navigate to /swagger/ui, you’ll immediately see those details.

API details displayed in Swagger

The next thing we’ll want to do is add a bit more information to some of our endpoints. We can do that using XML Comments in our code.

First, on your project properties, under build, check the box for XML documentation file

Now Swashbuckle can make use of the XML comments, so let’s add some to our controller. I’m going to modify the post method, simply adding a few example return types:

// POST api/values
/// <response code="400">Invalid Model</response>
/// <response code="200">Posted Supplier</response>
[HttpPost]
public void Post([FromBody]string value)
{
}

We now just need to make Swashbuckle include these comments, so we do that once again in Startup.cs, in our call to ConfigureSwaggerGen, add this to the options:

var basePath = PlatformServices.Default.Application.ApplicationBasePath;
options.IncludeXmlComments(basePath + "\\SwashbuckleExample.xml");

And the using statement for PlatformServices:

using Microsoft.Extensions.PlatformAbstractions;

The name of the XML file will depend on your project name, and can be found in your debug folder. This code simple finds the file, and passes the address through to the Swagger options.

If you run the code and once again navigate to swagger, open your method, you’ll see our response messages

XML response codes displayed in Swagger

Now run and go to /swagger/ui again, check the method and see the snazzy new response codes!

Another useful thing to do, when accepting a complex object as a parameter, is to have a sample model set up for swagger to use. If you’re adding validation to your model, it saves users worrying about it so much if they can just click the sample and have that sent through.

So first, we’ll need an example class set up, this is the one I created, imaginatively called ExampleModel:

public class ExampleModel
{
    public string Name { get; set; }
 
    [RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")]
    public string Email { get; set; }
 
    public DateTime TheTime { get; set; }
 
    public Decimal RanOutOfIdeas { get; set; }
}

I’ve added a Regular Expression annotation to the email, just to give an example of when a sample model would be of use. Not having a sample model gives the value string for all strings, which leaves your default value invalid. Adding a sample model avoids this.

So now we have a model, we need to create a SchemaFilter class. This class will implement SwaggerGen’s ISchemaFilter interface.

Implement the interface, and in the Apply method we want to check that the type matches our class, and if so, set the schema example to an instance of our class:

public class SchemaExample : ISchemaFilter
{
    public void Apply(Schema model, SchemaFilterContext context)
    {
        if (context.SystemType == typeof(ExampleModel))
        {
            model.Example = new ExampleModel
            {
                Name = "Test Name",
                Email = "test@email.com",
                TheTime = DateTime.UtcNow,
                RanOutOfIdeas = 3.2M
            };
        }
    }
}

Now there are two ways of registering this, one is to add the filter as an attribute to your model class. Whenever that model is used, your schema filter will apply. The other way is to add it to the options when you configure SwaggerGen. For this example I’ll be adding it to the model for this example, so annotate your model class like so:

SwaggerSchemaFilter(typeof(SchemaExample))]

And you’ll need the Annotations using statement:

using Swashbuckle.SwaggerGen.Annotations;

And finally modify your controller method to take in the model class as a parameter:

// POST api/values
/// <response code="400">Invalid model - Bad Request!</response>
/// <response code="200">Successfully posted the model - OK!</response>
[HttpPost]
public void Post([FromBody]ExampleModel value)
{
}

Now if you run the code, navigate to Swagger, and open that controller method, you’ll see your example model set out to the right hand side, and clicking in the box will add that model to the value text box, allowing you to post data without worrying about anything.

Example model in Swagger

Getting up and running with Swagger/Swashbuckle is as easy as that!

I’m still playing with this and learning more, as I’m sure there’s plenty of cool stuff I haven’t found yet, so will post an update if I find out anything useful.

And please feel free to let me know if you’ve come across anything I should know about!

comments powered by Disqus