Reputation: 1988
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
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