8

I'm using the JSONAPI specifications from jsonapi.org, then I'm using the JsonApiSerializer to accomplish the JSONAPI specification, so my response and request body looks like:

{    
    "data": {
    "type": "articles",
    "id": "stringId",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    }
}

I have an entity "Article" it looks like:

public class Article
{
     public string Id { get; set; }
     public string title { get; set; }
}

Then I'm trying to use Swashbuckle Swagger for document my API, but in the Swagger UI my example Request and Response body looks like:

{
     "id": "string",
     "title": "string"
}

I think swagger is ignoring the JsonApiSerializer, there is a way to change the default serializer for swagger and use my own serializer?

My Startup.cs looks like:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(
                    "v1",
                    new OpenApiInfo
                    {
                        Version = "v1",
                        Title = "HTT API",
                        Description = "HTT API provides methods to handle events",
                        Contact = new OpenApiContact
                        {
                            Name = "htt",
                            Email = "info@htt.com",
                        },
                    });

                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });


            services.AddAPIDependencies(this.Configuration);
            services.AddControllers().AddNewtonsoftJson(
            options =>
            {
                var serializerSettings = new JsonApiSerializerSettings();
                options.SerializerSettings.ContractResolver = serializerSettings.ContractResolver;
                options.SerializerSettings.Converters.Add(new StringEnumConverter());
            });

            services.Configure<DatabaseSettings>(
            this.Configuration.GetSection(nameof(DatabaseSettings)));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "HTT API V1");
            });

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
  • Net core 3.1
  • Swashbuckle.AspNetCore 5.0.0
Ian Kemp
  • 24,155
  • 16
  • 97
  • 121
HTT
  • 83
  • 3

1 Answers1

2

You can generate example swagger requests & responses using Swashbuckle.AspNetCore.Filters.

Example copied from one of the referenced blog posts:

[Route(RouteTemplates.DeliveryOptionsSearchByAddress)]
[SwaggerRequestExample(typeof(DeliveryOptionsSearchModel), typeof(DeliveryOptionsSearchModelExample))]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(DeliveryOptionsModel), Description = "Delivery options for the country found and returned successfully")]
[SwaggerResponseExample(HttpStatusCode.OK, 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)
{

Notice the use of various *Example models. Each such type should implement IExamplesProvider and generate sample data:

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

Notice that your example provider should return instances of the type you specified in the SwaggerResponse attribute (e.g. DeliveryOptionsSearchModel).

Don’t forget to enable the ExamplesOperationFilter when you enable Swagger:

services.AddSwaggerGen(c =>
{
     c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
     c.OperationFilter<ExamplesOperationFilter>();
}

UPDATE

The documentation appears to be somewhat out of date. I had to do the following to make the example provider kick in:

services.AddSwaggerExamplesFromAssemblyOf<DeliveryOptionsSearchModelExample>();

.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo {Title = "Elsa", Version = "v1"});
    c.ExampleFilters();
})
Sipke Schoorstra
  • 1,716
  • 1
  • 14
  • 21