How to make Swagger show examples of objects returned from the API?

Casey Crookston picture Casey Crookston · Mar 2, 2018 · Viewed 17.1k times · Source

I am creating a set of API's for the first time. Here's one of the methods:

    // GET: api/Doors/0
    /// <summary>
    /// Get a list of all doors for a given organization.
    /// </summary>
    /// <param name="organizationSys">The Organization ID for which all doors should be retreived.</param>
    /// <returns></returns>
    [Route("{organizationSys:int}")]
    public IHttpActionResult Get(int organizationSys)
    {
        try
        {
            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters.Add("@OrganizationSys", organizationSys);
            List<Door> doors = Repository<Doors>.GetList("WHERE OrganizationSys = @OrganizationSys", parameters).ToList();
            if (doors == null || doors.Count() == 0)
                return Content(HttpStatusCode.NotFound, RejectionMessage.NoItemsFound);

            return Ok(doors);
        }
        catch (Exception ex)
        {
            return Content(HttpStatusCode.BadRequest, ex.Message);
        }
    }

I've set up a Unit Test to this endpoint, and it works perfectly. However, I do have one question.

In Swagger, I'd like to show an example of the data object that will be returned. The only return type on the method is IHttpActionResult so I'm not surprised it's not showing the data model in Swagger. So, what do I need to change with this method so that the return object (in this case List<Door>) will be more visible?

Does Swashbuckle support this?

Thanks!

Answer

quetzalcoatl picture quetzalcoatl · Mar 2, 2018

That should be pretty straightforward:

[Route("{organizationSys:int}")]
[ProducesResponseType(typeof(List<Door>), 200)]
[ProducesResponseType(typeof(string), 400)]
public IHttpActionResult Get(int organizationSys)

Note that since you have 2 exit points: one normal return with data, and a catch that returns error message, I've defined in the example above two possible result types:

  • http:200(OK) with List<Door>
  • http:400(BadRequest) with string

Swashbuckle Swagger infrastructure will read that and provide very rough examples of the data for these cases.

However, if you need more detailed examples (i.e. with some reasonable field values) then you will have to implement so-called "example provider". See here for details and quick tutorial, in short:

[SwaggerRequestExample(typeof(DeliveryOptionsSearchModel), typeof(DeliveryOptionsSearchModelExample))]
public async Task<IHttpActionResult> DeliveryOptionsForAddress(DeliveryOptionsSearchModel search)

and

public class DeliveryOptionsSearchModelExample : IExamplesProvider
{
  public object GetExamples()
  {
    return new DeliveryOptionsSearchModel
    {
        Lang = "en-GB",
        Currency = "GBP",
        Address = new AddressModel
        {
            Address1 = "1 Gwalior Road",
            Locality = "London",
            Country = "GB",
            PostalCode = "SW15 1NP"
        },
        Items = new[]
        {
            new ItemModel
            {
                ItemId = "ABCD",
                ItemType = ItemType.Product,
                Price = 20,
                Quantity = 1,
                RestrictedCountries = new[] { "US" }
            }
        }
    };
}

The example provider works in a really simple way: whatever the provider returns, it is serialized to JSON and returned as the example for given data type. Just like that.

Now, if your method returned DeliveryOptionsSearchModel, the provider would use this data above directly.

Or, if your method returned a larger object, composed of DeliveryOptionsSearchModel and few others, then Swagger would use this provider for one part of the response example, and other provider(s) (or default rough examples) for all other parts of the large object.


All of the above was for Net Core.

If you use 'normal' Net 4.5/4.6/4.7, then this way is not available, as the Attribute class does not exist. In AspMvc for Net 4.x there's only [ResponseType(typeof(..))] attribute that allows to define a single return type. That's OK for most of the times. However, if you really need to differentiate return types over response codes, or if you need to provide good examples, that's a problem.

However! Some good people solved that already. See this article. It describes NuGet Swagger.Examples, I believe it's for non-core, and it aims at providing better result descriptions.

It defines another attribute - [SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable... to define possible result codes and result types and provides plugin for Swagger to make use of that attribute.

It also provides another attribute, [SwaggerResponseExample... that allows you to define the result-example provider, which can provide a custom good example with data, just like IExampleProvider described above for Core. Neat!