How to generate JSON example values for class, just like Swagger does for example response?

Viewed 1804

I'm using Swagger with my ASP.NET Core application and for a HTTP POST endpoint returning Blog model:

[HttpPost]
[ProducesResponseType(typeof(Blog), StatusCodes.Status200OK)]
public IActionResult AddBlog([FromBody] string name)
{
    // Code removed for brevity...
    return Ok(newBlog);
}

Blog:

public Blog
{
    public int Id { get; set; }

    public string Name { get; set; }
}

Swagger in its UI will show example response for that endpoint:

{
  "Id": 0,
  "Name": "string"
}

What I'd like to do is to generate such example values in JSON for type of class I provide and where I need it, which is somewhere else in my application like:

var json = exampleValuesGenerator.Generate(typeof(Blog));

Is this possible?

4 Answers

Closest I've come to the desired generator is by using a library NJsonSchema. Thanks to @Helen for giving me valuable directions to Json Schema. Usage example below:

public string Generate(Type type)
{
    return JsonSchema
        .FromType(type)
        .ToSampleJson()
        .ToString();
}

It isn't perfect though. For example, for model defined as follows:

public class User
{
    public string String { get; set; }
    public int Int { get; set; }
    public double Double { get; set; }
    public float Float { get; set; }
    public short Short { get; set; }
    public byte Byte { get; set; }
    public long Long { get; set; }
    public decimal Decimal { get; set; }
    public DateTime DateTime { get; set; }
    public TimeSpan TimeSpan { get; set; }
    public bool Bool { get; set; }
    public BindingFlags Enum2 { get; set; }
    public Blog NestedObject { get; set; }
    public Blog[] ArrayOfObjects { get; set; }
    public int[] ArrayOfValues { get; set; }
}

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
}

it generates a sample JSON:

{
  "String": "String",
  "Int": 0,
  "Double": 0,
  "Float": 0,
  "Short": 0,
  "Byte": 0,
  "Long": 0,
  "Decimal": 0,
  "DateTime": "2020-08-02T19:43:59.8759099+00:00",
  "TimeSpan": "TimeSpan",
  "Bool": false,
  "Enum2": 0,
  "NestedObject": null,
  "ArrayOfObjects": [
    {
      "Id": 0,
      "Name": "Name"
    }
  ],
  "ArrayOfValues": [
    0
  ]
}

Sadly NestedObject property is null when it shouldn't be and floating point types should have example value suggesting they are indeed floating type, not just 0 suggesting that they are of integer type. So yeah, it could be improved. But it's definitely better than nothing!

Yes, it's possible to generate such example values for responses and for POST request. For Get requests, it's difficult, see my question here: SwashBuckle Swagger-UI Example Request for HTTP GET Method with FromQuery Attribute

Have a look at the NuGet package Swashbuckle.AspNetCore.Filters:

You can define an example response such as this:

public class BlogExample : IExamplesProvider<Blog>
{
    public Blog GetExamples()
    {
        return new Blog()
        {
            Id = 123,
            Name = "John Smith"
        };
    }
}

SwaggerUI will then show these values instead of the empty default values.

NJsonSchema is fine to generate the sample json for a CLR type:

var sampleJson = JsonSchema.FromType(typeof(Foo)).ToSampleJson().ToString();

Hoverer,if Foo has nested complex type as properties ,you have to add additional attribute such as [Required] to make things work.

As a result ,i prefer to combine AutoFixture with NJsonSchema to generate the sample json,here is the example:

[Fact]
public void Test1()
{
  var sampleJson = JsonConvert.SerializeObject(new Fixture().Create<Foo>());
  var str = JsonSchema.FromSampleJson(sampleJson).ToSampleJson();
  File.WriteAllText(Path.Combine(Path.GetTempPath(),Path.GetTempFileName()),str.ToString());
}

You can use any JSON library and serialise an empty object.

Using newtonsoft JSON

var json = JsonConvert.SerializeObject(new Blog());
Related