JohnB
JohnB

Reputation: 1793

Default model example in Swashbuckle (Swagger)

I'm running ASP WebAPI 2 and successfully installed Swashbuckle. I am trying to figure out how one defines what the default schema values are?

For example, on the Swagger live demo site they changed the default value of pet to "doggie". They also defined the allowable values for status. (Live Demo)

Example 1 Example 2

Upvotes: 19

Views: 22676

Answers (6)

Szhlopp
Szhlopp

Reputation: 51

Using .NET 5 with Swashbuckle.AspNetCore 5.6.3, the only way I could get this to work efficiently is this:

public class ExampleDocFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        string ToCamelCase(string name) => char.ToLowerInvariant(name[0]) + name.Substring(1);
        if (schema.Properties == null) return;

        var setProperties = context.Type.GetProperties().ToList().Where(f => f.GetCustomAttribute<DefaultValueAttribute>() != null).Where(f => schema.Properties.Any(n => n.Key.Equals(ToCamelCase(f.Name)))).ToDictionary(f => f, f => f.GetCustomAttribute<DefaultValueAttribute>());
        foreach (var prop in setProperties) schema.Properties[ToCamelCase(prop.Key.Name)].Example = OpenApiAnyFactory.CreateFor(schema.Properties[ToCamelCase(prop.Key.Name)], prop.Value.Value);

    }
}

To use this - in your startup.cs:

services.AddSwaggerGen(swagger => {
  ...
  swagger.SchemaFilter<ExampleDocFilter>(); 
}); 

Upvotes: 0

0909EM
0909EM

Reputation: 5027

Stumbled across this just now, you can also set the tag in the XML documentation, in one of my models, I have this defined

    /// <summary>
    /// Note content
    /// </summary>
    /// <example>Any text for a note.</example>
    public string Note { get; set; }

which ends up looking like this in the swagger documentation when selecting "Try It Now"

enter image description here

Hope that helps someone!

Upvotes: 1

bmatchey
bmatchey

Reputation: 31

I know this thread is quite old, but I wanted to share my solution which creates a custom constructor just for the Swagger example schema.

In my model:

/// <summary>
/// Supply a custom constructor for Swagger where you can apply defaults to control the example schema.  
/// The constructor must have one parameter of type System.Reflection.ParameterInfo[].
/// Note: Setting a property to null will prevent it from showing in the Swagger example.
/// </summary>System.Reflection.ParameterInfo[].
/// </summary>
public class SwaggerConstructor : Attribute { }

In SwaggerConfig.cs:

c.SchemaFilter<ApplySchemaVendorExtensions>();

The schema extension:

    public class ApplySchemaVendorExtensions : ISchemaFilter
{
    public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
    {
        ConstructorInfo constructor = type.GetConstructors().FirstOrDefault(c => c.GetCustomAttribute<SwaggerConstructor>() != null);
        if (constructor != null)
        {
            schema.example = constructor.Invoke(new object[] { constructor.GetParameters() });
        }
    }
}

Usage:

    [SwaggerConstructor]
    public MyClass(System.Reflection.ParameterInfo[] decoy) : base()
    {
        MyProperty = false;
    }

Upvotes: 3

Andy Hoyle
Andy Hoyle

Reputation: 846

An example Model Schema can be defined by implementing ISchemaFilter and registering it using the following:

httpConfig 
    .EnableSwagger(c =>
         {
             c.SchemaFilter<AddSchemaExamples>()
         });

An example implementation is provided here:

public class AddSchemaExamples : ISchemaFilter
{
    public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
    {
        if (type == typeof(Product))
        {
            schema.example = new Product
                {
                    Id = 123,
                    Type = ProductType.Book,
                    Description = "Treasure Island",
                    UnitPrice = 10.0M
                };
        }
    }
}

Source: https://github.com/domaindrivendev/Swashbuckle/issues/162

Upvotes: 10

Philipp Michalski
Philipp Michalski

Reputation: 606

Well the code of vgaspar.trivix did not work completly for me, the default values did not get set for the schema. Also i got an NullPointerException. I managed to get it working as intended by editing the Apply method and manipulated the schemaRegistry like this:

public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
    if (operation.parameters == null)
        return;
    IDictionary<string, object> parameterValuePairs =
    GetParameterValuePairs(apiDescription.ActionDescriptor);

    foreach (var param in operation.parameters)
    {
        if (param.schema != null && param.schema.@ref != null)
        {
            string schemaName = [email protected]('/').LastOrDefault();
            if (schemaRegistry.Definitions.ContainsKey(schemaName))
                foreach (var props in schemaRegistry.Definitions[schemaName].properties)
                {
                    if (parameterValuePairs.ContainsKey(props.Key))
                        props.Value.@default = parameterValuePairs[props.Key];
                }
        }
        var parameterValuePair = parameterValuePairs.FirstOrDefault(p => p.Key.IndexOf(param.name, StringComparison.InvariantCultureIgnoreCase) >= 0);
        param.@default = parameterValuePair.Value;
    }
}

Upvotes: 12

vgaspar.travix
vgaspar.travix

Reputation: 326

I managed to get this working by following what's on this link:

https://github.com/domaindrivendev/Swashbuckle/issues/69#issuecomment-53953785

In short this is what needs to be done:

  1. Create the classes SwaggerDefaultValue and AddDefaultValues as described in the link. Some changes that I did:

    public class SwaggerDefaultValue : Attribute
    {
        public string Name { get; set; }
        public string Value { get; set; }
    
        public SwaggerDefaultValue(string value)
        {
            this.Value = value;
        }
    
        public SwaggerDefaultValue(string name, string value) : this(value)
        {
            this.Name = name;
        }
    }
    
    public class AddDefaultValues : IOperationFilter
    {
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            IDictionary<string, object> parameterValuePairs =
            GetParameterValuePairs(apiDescription.ActionDescriptor);
    
            foreach (var param in operation.parameters)
            {
                var parameterValuePair = parameterValuePairs.FirstOrDefault(p => p.Key.IndexOf(param.name, StringComparison.InvariantCultureIgnoreCase) >= 0);
                param.@default = parameterValuePair.Value;
            }
        }
    
        private IDictionary<string, object> GetParameterValuePairs(HttpActionDescriptor actionDescriptor)
        {
            IDictionary<string, object> parameterValuePairs = new Dictionary<string, object>();
    
            foreach (SwaggerDefaultValue defaultValue in actionDescriptor.GetCustomAttributes<SwaggerDefaultValue>())
            {
                parameterValuePairs.Add(defaultValue.Name, defaultValue.Value);
            }
    
            foreach (var parameter in actionDescriptor.GetParameters())
            {
                if (!parameter.ParameterType.IsPrimitive)
                {
                    foreach (PropertyInfo property in parameter.ParameterType.GetProperties())
                    {
                        var defaultValue = GetDefaultValue(property);
    
                        if (defaultValue != null)
                        {
                             parameterValuePairs.Add(property.Name, defaultValue);
                        }
                    }
                }
            }
    
            return parameterValuePairs;
        }
    
        private static object GetDefaultValue(PropertyInfo property)
        {
            var customAttribute = property.GetCustomAttributes<SwaggerDefaultValue>().FirstOrDefault();
    
            if (customAttribute != null)
            {
                return customAttribute.Value;
            }
    
            return null;
        }
    }
    
    1. Edit your SwaggerConfig and add the AddDefaultValues class to the OperationFilters:

      GlobalConfiguration.Configuration
          .EnableSwagger(c => {
                ...
                c.OperationFilter<AddDefaultValues>()
                ...
           });
      
    2. Now for the parameters I want default values I just add the following:

      public IHttpActionResult Put([FromBody]Pet pet)
      {
         ...
         return Ok();
      }
      
      public class Pet {
          [SwaggerDefaultValue("doggie")]
          public string Name { get; set; }
      
          [SwaggerDefaultValue("available")]
          public string Status;
      
          ...
      }
      

Upvotes: 14

Related Questions