Quantcast
Channel: mattfrear – Matt's work blog
Viewing all articles
Browse latest Browse all 53

Generating Swagger example requests with Swashbuckle

$
0
0

This is a follow on from my post from last year about Generating example Swagger responses.

It can also be useful to generate example requests, and in this post I will show you how.

Create a new SwaggerRequestExamplesAttribute

[AttributeUsage(AttributeTargets.Method)]
public sealed class SwaggerRequestExamplesAttribute : Attribute
{
    public SwaggerRequestExamplesAttribute(Type responseType, Type examplesProviderType)
    {
        ResponseType = responseType;
        ExamplesProviderType = examplesProviderType;
    }

    public Type ExamplesProviderType { get; private set; }

    public Type ResponseType { get; private set; }
}

Decorate your controller methods with it:

[Route(RouteTemplates.DeliveryOptionsSearchByAddress)]
[SwaggerRequestExamples(typeof(DeliveryOptionsSearchModel), typeof(DeliveryOptionsSearchModelExample))]
[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, should not return sensitive information")]
public async Task<IHttpActionResult> DeliveryOptionsForAddress(DeliveryOptionsSearchModel search)
{

Now implement it, in this case via a DeliveryOptionsSearchModelExample, which will generate the example data. It should return the type you specified when you called SwaggerRequestExamples.

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" }
                }
            }
        };
    }

Finally, you’ll need to change the ExamplesOperationFilter we implemented in my previous post:

public class ExamplesOperationFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
    SetRequestModelExamples(operation, schemaRegistry, apiDescription);
    SetResponseModelExamples(operation, schemaRegistry, apiDescription);
}

private static void SetRequestModelExamples(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
    var requestAttributes = apiDescription.GetControllerAndActionAttributes<SwaggerRequestExamplesAttribute>();

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

        var request = operation.parameters.FirstOrDefault(p => p.@in == "body" && p.schema.@ref == schema.@ref);

        if (request != null)
        {
            var provider = (IExamplesProvider)Activator.CreateInstance(attr.ExamplesProviderType);

            var parts = schema.@ref.Split('/');
            var name = parts.Last();

            var definitionToUpdate = schemaRegistry.Definitions[name];

            if (definitionToUpdate != null)
            {
                definitionToUpdate.example = ((dynamic)FormatAsJson(provider))["application/json"];
            }
        }
    }
}

private static void SetResponseModelExamples(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 != null && x.Value.schema != null && x.Value.schema.@ref == schema.@ref);

        if (response.Equals(default(KeyValuePair<string, Response>)) == false)
        {
            if (response.Value != null)
            {
                var provider = (IExamplesProvider)Activator.CreateInstance(attr.ExamplesProviderType);
                response.Value.examples = FormatAsJson(provider);
            }
        }
    }
}

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

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

    return ConvertToCamelCase(examples);
}
}

Don’t forget to configure the ExamplesOperationFilter when you enable Swagger, as before:

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.

Capture

And the best part is, when you’re using swagger-ui, now when you click the example request in order to populate the form, instead of getting an autogenerated request like this:

Untitled

You’ll get your desired example, like this:

Capture2

 



Viewing all articles
Browse latest Browse all 53

Trending Articles