Generating Swagger example responses with Swashbuckle

Swashbuckle is a tool for generating Swagger, the API description language, from your ASP.NET Web Api solution.
Using Swashbuckle, which provides Swagger-UI, you can create pretty living documentation of your web api, like this:
swagger

Documenting the Response

In this post I am going to show you how to document the Response, and a new way to generate some response examples.

You can specify the type of response for Swashbuckle a number of ways. Consider a simple API endpoint which returns a list of Countries:

public class CountriesController : DefaultController
{
    [HttpGet]
    public async Task<HttpResponseMessage> Get()
    {
        var resource = new List<Country>
        {
            new Country {Code = "AR", Name = "Argentina"},
            new Country {Code = "BR", Name = "Brazil"},
            // etc etc omitted for brevity
        };

        return Request.CreateResponse(HttpStatusCode.OK, resource);
    }
}

One way of describing the response code and content for Swashbuckle is using a combination of XML comments, and the ResponseType attribute, like so:

/// <response code="200">Countries returned OK</response>
[HttpGet]
[ResponseType(typeof(IEnumerable<Country>))]
public async Task<HttpResponseMessage> Get()
{

However, this only allows for one type of response.

If your API method can return multiple types, i.e. in the case of an error, then you can use the new SwaggerResponse attribute:

[HttpGet]
[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)
{

The Swagger 2.0 spec allows for examples to be added to the Response. However, at time of writing Swashbuckle doesn’t support this. Fortunately Swashbuckle is extendible so here is a way of doing it.

Create a new SwaggerResponseExamplesAttribute.

public class SwaggerResponseExamplesAttribute : Attribute
{
    public SwaggerResponseExamplesAttribute(Type responseType, Type examplesType)
    {
        ResponseType = responseType;
        ExamplesType = examplesType;
    }

    public Type ResponseType { get; set; }
    public Type ExamplesType { get; set; }
}

Decorate your methods with it:

[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponseExamples(typeof(IEnumerable<Country>), typeof(CountryExamples))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)

Now you’ll need to add an Examples class, which will generate the example data

public interface IProvideExamples
{
    object GetExamples();
}

public class CountryExamples : IProvideExamples
{
    public object GetExamples()
    {
        return new List<Country>
        {
            new Country {Code = "AA", Name = "Test Country"},
            new Country {Code = "BB", Name = "And another"}
        };
    }
}

Now you can add an ExamplesOperationFilter which implements Swashbuckle’s IOperationFilter.

public class ExamplesOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var responseAttributes = apiDescription.GetControllerAndActionAttributes<SwaggerResponseExamplesAttribute>();

        foreach (var attr in responseAttributes)
        {
            var schema = schemaRegistry.GetOrRegister(attr.ResponseType);

            var response = operation.responses.FirstOrDefault(x => x.Value.schema.type == schema.type && x.Value.schema.@ref == schema.@ref).Value;

            if (response != null)
            {
                var provider = (IProvideExamples) Activator.CreateInstance(attr.ExamplesType);
                response.examples = FormatAsJson(provider);
            }
        }
    }

    private static object FormatAsJson(IProvideExamples provider)
    {
        var examples = new Dictionary<string, object>()
        {
            {
                "application/json", provider.GetExamples()
            }
        };

        return ConvertToCamelCase(examples);
    }

    private static object ConvertToCamelCase(Dictionary<string, object> examples)
    {
        var jsonString = JsonConvert.SerializeObject(examples, new JsonSerializerSettings() {ContractResolver = new CamelCasePropertyNamesContractResolver()});
        return JsonConvert.DeserializeObject(jsonString);
    }
}

And finally configure it when you configure Swashbuckle’s startup.

configuration
    .EnableSwagger(c =>
    {
        c.OperationFilter<ExamplesOperationFilter>();
    })
    .EnableSwaggerUi();

Now that we’ve done all that, we should see the examples output in our swagger.json file, which you can get to by starting your solution and navigating to /swagger/docs/v1.

response

And then, when you browse the swagger-ui at /swagger, instead of an autogenerated example like this:
response old

You’ll see your desired example, like this:
response new

Be sure to check out Part 2, where we again use Swashbuckle to generate example requests.

Advertisements

24 thoughts on “Generating Swagger example responses with Swashbuckle

  1. We were rockin’ swagger briefly here for our web APIs (Java though, not .net). Has to be one of the most incongruently named technologies out there.

    Good to hear swashbuckle is continuing the tradition.

  2. Thanks for the article, helped me construct my own example response scheme. Have you tried doing the same for providing example values to HTTP POST request parameters which are given as JSON in the request body? Would be nice to hear if you have any insight how to go about those.

  3. I have both [ResponseType] and [SwaggerResponse] attributes on my controller methods. When I enable xml comments, these are not reflected anymore and my documentation shows an empty response object.

    Is there any way to use xml comments for summary, remarks, etc and still have response types generated from code?

    • Hmm yes I think it should work – in our solution we have both xml comments and SwaggerResponse.

      It might be worth checking on the Swashbuckle github page as things may have changed in newer versions.

  4. Hi
    I have done the same thing, but i am unable to see the examples values what I defined the examples class.
    Showing only default values.

    Regards,
    Ajay

  5. How have the response several requests bad errors with different messages? And that appears in the documentation swagger

    Regards, Michel

    • Just add multiple SwaggerResponse attributes to your controller method, e.g.

      [SwaggerResponse(HttpStatusCode.OK, Type = typeof(DeliveryOptionsModel), Description = “Delivery options for the country found and returned successfully”)]
      [SwaggerResponseExamples(typeof(DeliveryOptionsModel), typeof(DeliveryOptionsModelExample))]
      [SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(ErrorsModel), Description = “An invalid or missing input parameter will result in a bad request”)]
      [SwaggerResponse(HttpStatusCode.InternalServerError, Type = typeof(ErrorsModel), Description = “An unexpected error occurred”)]
      public async Task DeliveryOptionsForCountry([FromUri]DeliveryOptionsForCountryRequestModel search)

      • ok, yes, I understand. But, and how do I several different messages of the same type of HTTP error, in case the bad request.
        Example:
        [Swagger Response (HttpStatusCode.BadRequest, Type = typeof (Error Model), Description = “Message 1”)]
        [Swagger Response (HttpStatusCode.BadRequest, Type = typeof (ErrorsModel), Description = “Message 2”)]
        [SwaggerResponse (HttpStatusCode.BadRequest, Type = typeof (ErrorsModel), Description = “Message 3”)]
        You understand?

  6. I’m not sure if what you want to generate is valid swagger.
    http://swagger.io/specification/#responsesDefinitionsObject

    Well, a response name (e.g. BadRequest) can only have one description, but I guess there’s nothing in the spec which says each name has to be unique.

    I don’t know the answer to your question, but you could try asking on Swashbuckle’s github page – the SwaggerResponse attribute is part of Swashbuckle and is not my work.

    Matt

  7. Hi, thanks for the great post. Is there any way to add request/response examples without using swagger specific attributes in controllers? Because I am looking for a way where controller classes need not be tightly coupled with swashbuckle.

  8. Matt,

    Like the post have a question I am not a .Net expert, but got Swashbuckle working and Auto-Generating the swagger documentation. Since we are using the Web API documentation generator we have one object type in the model that is wonky from a REST API point of view.

    The Model definition looks like this (replaced some values for ease of reading) Engine.Api.Facade.ApiResult[System.Collections.Generic.IEnumerable[Engine.Api.ResourceModels.Public.Reporting.Performance.PerformanceByDayReportRow]] {…}

    So wondering, based on what I read here, I can generate custom data definition to remove the IEnumerable (this being REST) and simplify things since no need to expose the underlying data structures.

    Is that a correct understanding?

    • Hi Kevin,

      No, I don’t think you are correct. If your model is an IEnumerable then by default Swashbuckle will report that. I’m not a Swashbuckle or a Swagger expert though.

      My post was describing how to add some example data to your Model so that you get useful data in the generated Swagger. You might be able to use it to change the shape of your model but I don’t think it would work (I haven’t tried it).

      There’s nothing wrong with returning an IEnumerable though. I guess you could put it in a container object to be my RESTy perhaps, but I don’t think that is necessary. e.g.

      public class Report
      {
      public IEnumerable Rows { get; set; }
      public int Count { get; set; }
      }

      • yeah I want it to me more “RESTy” as IEnumerable is really not in any spec. That said I am exploring some options and our devs are looking at possible way to return a more REST like documentation response.

        I’ll do my best to update this if I glean anything useful

  9. My “X.Value.schema” is Null. Here is the comments i have above my method. Any ideas what I am missing?

    ///
    /// Post for entry properties
    ///
    ///
    /// This is the example
    ///
    ///
    /// LanguageID will default to 0.
    ///
    /// POST /PropertyEntry
    /// {
    /// “PropertyIds”: [
    /// 100,200,240
    /// ],
    /// “EntryIds”: [
    /// 15888,15889,15890
    /// ],
    /// “Language”: “en”,
    /// }
    ///
    ///
    /// Returns property Range
    /// Example: returns new item
    /// Example: Returns the range
    /// Example: If the item is null

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