Import OpenAPI 2.0 Postman collection and all POST request bodies are displayed as x-www-form-urlencoded, instead of raw JSON

Viewed 711

What I am using?

.NET Framework 4.8
Postman Version 7.19.1
Swashbuckle 5.6.0, nugget package


Problem?

I have a big API using Swagger (Swashbuckle) and I want to import the Open API schema to Postman as a collection.
After going on {myUrl}/swagger/docs/v1 and pasting the schema in Postman I've noticed that all my Post requests were 'broken'. When going to Body it was shown as "application/x-www-form-urlencoded", not as raw JSON body.

enter image description here

Instead, it looks like this:

enter image description here

My schema:

{
    "swagger": "2.0",
    "info": {
        "version": "v1",
        "title": "My API"
    },
    "host": "localhost:51209",
    "schemes": [
        "http"
    ],
    "paths": { },
    "definitions": { }
}

paths and definitions are not empty, they contain a lot of API calls, that's why I will pick just one POST method from them because all are with the same issue.

Here is one example of paths object and the property "consumes" in it:

"/api/MyController/MyMethod": {
        "consumes": [
            "application/json",
            "text/json",
            "application/xml",
            "text/xml",
            "application/x-www-form-urlencoded"
        ]
}

As it seems the problem is in the consumes object property that has an array of strings as values and one of them is "application/x-www-form-urlencoded".

I have no 'special' attributes above my action or controller in the .NET Web API.

[HttpPost]
[Route("MyMethod")]
public IHttpActionResult MyMethod(List<JobHeaderInputModel> jobHeaderList)

I know there is a Consumes attribute for ASP Net Core, but I am on .NET Framework.

1 Answers

Solution:

I saw this amazing article and implemented the solution there:

Created a custom attribute:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class SwaggerConsumesAttribute : Attribute
{
    public SwaggerConsumesAttribute(params string[] contentTypes)
    {
        this.ContentTypes = contentTypes;
    }

    public IEnumerable<string> ContentTypes { get; }
}

After that create an OperationFilter class for Swagger:

public class ConsumesOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var attribute = apiDescription.GetControllerAndActionAttributes<SwaggerConsumesAttribute>().SingleOrDefault();
        if (attribute == null)
        {
            return;
        }

        operation.consumes.Clear();
        operation.consumes = attribute.ContentTypes.ToList();
    }
}

And finally, just register the OperationFilter in SwaggerConfig.cs as follows:

c.OperationFilter<ConsumesOperationFilter>();
Related