Swashbuckle.aspnetcore: Is it possible to specify a required body type?

Created on 1 Nov 2016  路  11Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

Like in Postman you can select:

  • form-data
  • x-www-form-urlencoded
  • binary

To encode this with attribute on controller's method.
So that consumer know how to call the method and corresponding header was sent from Swagger UI.

Most helpful comment

I have the same problem. With the version 1.2.0 the following condition worked:

public IActionResult CreateToken([FromForm]LoginViewModel login, [FromHeader(Name = "grant_type")] string grantType)

with

public class LoginViewModel
{
  [Required]
  public string UserName { get; set; }
  [Required]
  public string Password { get; set; }
  public int CompanyNumber { get; set; } = 0;
}

The Swagger UI generates the following CURL output and I can get the auth token:

curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' --header 'grant_type: password' -d 'UserName=user&Password=password&CompanyNumber=111' 'http://localhost:5001/token'

The current version 2.3.0 produces the following CURL output and my view model is not filled:

curl -X POST "http://localhost:5001/token" -H "accept: application/json" -H "grant_type: password" -H "Content-Type: undefined" -d "UserName=user&Password=password&CompanyNumber=111"

The difference is, that the older version uses Content-Type: application/x-www-form-urlencoded and the new one Content-Type: undefined.

Is there a reason for different content type generation?

All 11 comments

If you use AspNet Core's built-in ProducesAttribute, it should do the trick. To see it action take a look at the "Basic" example:

https://github.com/domaindrivendev/Ahoy/blob/master/test/WebSites/Basic/Controllers/CrudActionsController.cs#L8

Your answer has suggested me an idea that if Produces exists then Consumes might be.
Looks like what I want is [Consumes("application/x-www-form-urlencoded")]

Is Consumes supported by Swagger and Swashbuckle?
I can't see any info in generated docs from ConsumesAttribute.

@domaindrivendev, is this feature聽in a backlog?

Swashbuckle generates Swagger Operation descriptions based on the corresponding _ApiDescription_ that's provided by ASP.NET Core. The "consumes" value is pulled from ApiDescription.SupportedRequestFormats. This is populated based on the presence of a ConsumesAttribute BUT only if there's a corresponding InputFormatter registered for the same MIME type.

However, as far as I can tell, you don't register InputFormatters for form-based MIME types. I may well be missing something but this seems like it could be an issue with the implementation of ApiExplorer in ASP.NET Core.

@rynowak - maybe there's something I'm missing here, would love to get your input?

@xperiandri - the best workaround for now would be a custom Operation Filter (see readme), that checks for the presence of the ConsumesAttribute and adds to the operation.Consumes property if application/x-www-form-urlencoded is specified. Here's an example:

public class FormDataOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        var formMediaType = context.ApiDescription.ActionAttributes()
            .OfType<ConsumesAttribute>()
            .SelectMany(attr => attr.ContentTypes)
            .FirstOrDefault(mediaType => mediaType == "application/x-www-form-urlencoded");

        if (formMediaType != null)
            operation.Consumes = new[] { formMediaType };
    }
}

@domaindrivendev I stumbled over this as well (already the second time). There is a nice StackOverflow answer about adding an attribute/filter specifying the data type.

Having something out of the box would be meaningful. Utilizing the Consumes attribute is maybe a bit tricky due to Controller level misuse of the attribute

I have the same problem. With the version 1.2.0 the following condition worked:

public IActionResult CreateToken([FromForm]LoginViewModel login, [FromHeader(Name = "grant_type")] string grantType)

with

public class LoginViewModel
{
  [Required]
  public string UserName { get; set; }
  [Required]
  public string Password { get; set; }
  public int CompanyNumber { get; set; } = 0;
}

The Swagger UI generates the following CURL output and I can get the auth token:

curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' --header 'grant_type: password' -d 'UserName=user&Password=password&CompanyNumber=111' 'http://localhost:5001/token'

The current version 2.3.0 produces the following CURL output and my view model is not filled:

curl -X POST "http://localhost:5001/token" -H "accept: application/json" -H "grant_type: password" -H "Content-Type: undefined" -d "UserName=user&Password=password&CompanyNumber=111"

The difference is, that the older version uses Content-Type: application/x-www-form-urlencoded and the new one Content-Type: undefined.

Is there a reason for different content type generation?

@WebDucer, I have the same problem when using FromFormAttribute.
for workaround I've used the following operation filter but this seems to be a bug and needs to be fixed

c# public class SwaggerConsumesOperationFilterX : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (context.ApiDescription.ParameterDescriptions.Select(pd => pd.ParameterDescriptor).OfType<ControllerParameterDescriptor>().Any(descriptor => descriptor.ParameterInfo.GetCustomAttribute<FromFormAttribute>() != null)) { operation.Consumes.Add("application/x-www-form-urlencoded"); } } }

Same here. Any updates?

I have the same exact problem with version 3.0.0, the issue is linked to [FromForm] attribute, I tried Consumes attribute with no luck.

I think this issue is now resolved with the following 2 changes that have been recently merged to master:

  1. Honor consumes and produces attributes (5d7d73e63e4b8af685f1b91d8a25b204f5f11449)
  2. Support form file parameters (af1ec16fded935d60ef13beae150e6e27155db9a)

Now, the consumes list (which drives Content-Type in the UI) will default to [ "multipart/form-data" ] when an operation has [FromForm] parameters. So, this should work out-of-the-box. Then, if you want to use the x-www-form-urlencoded flavor, you can explicitly specify that with the ConsumesAttribute:

[HttpPost("login")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Login([FromForm]LoginForm loginForm)
...

This will be generally available with the 4.0.0 release (coming soon). In the meantime you can try it out by downloading the preview package from myget.org:
https://www.myget.org/feed/domaindrivendev/package/nuget/Swashbuckle.AspNetCore

Was this page helpful?
0 / 5 - 0 ratings