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.
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.
You’ll get your desired example, like this:
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
Clik here to view.
