Anonymous
Anonymous

Reputation: 1988

Swagger generates incorrect URL for dictionary in ASP.CORE 3

Swagger generates incorrect URL when model extracted from query string has a dictionary as one of its properties. How to tell Swagger to change format of the dictionary in the URL or to define input parameters schema manually, without auto-generation? Tried to use Swashbuckle and NSwag.

Controller

public class RecordsController : ControllerBase
{
  [HttpGet]
  [Route("services/records")]
  public async Task<IActionResult> Records([FromQuery] QueryModel queryModel)
  {
    return null;
  }
}

Input Model - Query String

public class QueryModel 
{
  public int Page { get; set; }
  public int Count { get; set; }
  public Dictionary<Columns, string> Conditions { get; set; }
}

Swagger UI shows this format for "Conditions" property on Query Model

{
  "UserId": "string",
  "GroupId": "string",
  "RecordId": "string"
}

Swagger generated URL - Open API v2 - will not be bound to "Conditions"

/services/records?Page=0&Count=5&Conditions={"UserId":"1"} 

Swagger generated URL - Open API v3 - will not be bound to "Conditions"

/services/records?Page=0&Count=5&UserId=1 

Custom URL - works as expected and initializes "Conditions" with { "UserId", "1" }

/services/records?Page=0&Count=5&Conditions[UserId]=1 

Question

How to enforce Swagger to render URL like PropertyName[Key]=Value for the property of type Dictionary?

Alternative question

Not a solution, but if I define default value for my input parameter this way, Swagger creates correct URL.

{
  "Conditions[UserId]": "1",
  "Conditions[GroupId]": "2"
}

URL is correct now and is properly bound to the model

/services/records?Page=0&Count=5&Conditions[UserId]=1&Conditions[GroupId]=2 

Is there a way to change default value displayed in Swagger for Dictionary input type?

Upvotes: 5

Views: 3001

Answers (1)

Edward Romero
Edward Romero

Reputation: 3106

You will need to set the query style deepObject for the query definition

This is currently supported by NSwag through SwaggerParameterStyle for which you will set value deepObject.

I was also curious how to do this without NSwag, so I took a look at https://editor.swagger.io/

Here you can provide it your static json swagger and it will generate you a server if you want to see a different way of creating the same setup

Sample model for dictionary

[DataContract]
public partial class Dictionary : IEquatable<Dictionary>
{ 
    /// <summary>
    /// Gets or Sets Word
    /// </summary>
    [DataMember(Name="word")]
    public string Word { get; set; }

    /// <summary>
    /// Gets or Sets Define
    /// </summary>
    [DataMember(Name="define")]
    public string Define { get; set; }

Sample Controller

    /// <summary>
    /// Get word definition
    /// </summary>
    /// <remarks>Get me the word definitions</remarks>
    /// <param name="dictionary">Status values that need to be considered for filter</param>
    /// <response code="200">successful operation</response>
    [HttpGet]
    [Route("/v2/book")]
    [ValidateModelState]
    [SwaggerOperation("BookGet")]
    public virtual IActionResult BookGet([FromQuery][Required()]Dictionary dictionary)

Raw Swagger example query

/book:
  get:
    summary: Get word definition
    description: Get me the word definitions
    parameters:
    - name: dictionary
      in: query
      description: Status values that need to be considered for filter
      required: true
      style: deepObject
      schema:
        type: object
        properties:
          word: 
            type: string
          define:
            type: string

Look at deepObject style in https://swagger.io/specification/

Upvotes: 0

Related Questions