Swashbuckle.webapi: Optional routeTemplate parameters is tagged as required in spec

Created on 18 Aug 2016  路  7Comments  路  Source: domaindrivendev/Swashbuckle.WebApi

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
public class ValuesController : ApiController
{
    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/<controller>/5
    public string Get(int id)
    {
        return "value";
    }
}

The path parameter gets documented as required in swagger.json:

{
  "/api/Values": {
    "get": {
      "operationId": "Values_Get"
    }
  },
  "/api/Values/{id}": {
    "get": {
      "operationId": "Values_Get",
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "type": "integer",
          "format": "int32"
        }
      ]
    }
  }
}

Same result using a nullable int

public class ValuesController : ApiController
{
    public string Get(int? id)
    {
        return "value";
    }
}

Or optional string

public class ValuesController : ApiController
{
    public string Get(string id = null)
    {
        return "value";
    }
}

All 7 comments

I did some more testing on how things are handled by asp.net:

/{id} is required

    public string Get(int id)

    public string Get(int? id)

    public string Get(string id)

/{id} is optional (but documented as required by Swashbuckle)

    public string Get(int? id = null)

    public string Get(string id = null)

Same here, it is annoying

Swagger doesn't support optional "path" parameters because the path (less query string) uniquely identifies an operation. It's opinionated on this matter - if you want to describe it via Swagger you'll need to split into separate operations.

NOTE: this is a Swagger constraint, not a Swashbuckle constraint

What if we look at the optional parameters as overloads instead?

This

 public string Get() {}
 public string Get(string id) {}

and this

 public string Get(string id = null) {}

could both be described in swagger as

{
  "/api/Values": {
    "get": {
      "operationId": "Values_Get"
    }
  },
  "/api/Values/{id}": {
    "get": {
      "operationId": "Values_Get_id",
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "type": "integer",
          "format": "int32"
        }
      ]
    }
  }
}

@moander - that's exactly the approach I would recommend. It keeps your contract intact and minimizes code changes because the new overloads can delegate to your existing method - which should be made private

IMO the v1.0 swagger/swaschbuckle version was better on it. It simply treated that optional parameter as a mandatory and at least the rest of the UI was working. For the given optional param. the generated command was not working, yet...

Now with v2.0 we simply get an error when hit swagger URL. The advice above also stinks, since it forces us to bypass exiting coding practices.

How to revert to v1.0 behaviour and add a big WARNING to the desc.?

@hidegh - please read the contribution guidelines and consider how you articulate your opinions, keeping in mind that SB is a free and open source project provided to you at no financial gain to its authors.

A more constructive and understanding argument is always more likely to be actioned. With that said, I agree that defaulting to required and not raising an error is a better experience for SB consumers. I will revert that change in the AspNetCore implementation

I'll also add that I have no plans to support optional path parameters by generating multiple operation descriptions within SB. I don't want to take on the additional complexity to support what I believe to be an anti-pattern.

Was this page helpful?
0 / 5 - 0 ratings