Quantcast
Viewing all articles
Browse latest Browse all 53

Generating Swagger example requests with Swashbuckle

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.

Image may be NSFW.
Clik here to view.
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:

Image may be NSFW.
Clik here to view.
Untitled

You’ll get your desired example, like this:

Image may be NSFW.
Clik here to view.
Capture2

 


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 53

Trending Articles