Skip to content

Commit ef5bcf6

Browse files
Merge pull request #1088 from microsoft/mk/fix-unexpected-collection-format
Fix unexpected collection format during V2 serialization
2 parents 0224604 + 257107c commit ef5bcf6

6 files changed

+59
-8
lines changed

src/Microsoft.OpenApi/Models/OpenApiParameter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Runtime;
67
using Microsoft.OpenApi.Any;
@@ -377,7 +378,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
377378
// allowEmptyValue
378379
writer.WriteProperty(OpenApiConstants.AllowEmptyValue, AllowEmptyValue, false);
379380

380-
if (this.In == ParameterLocation.Query)
381+
if (this.In == ParameterLocation.Query && "array".Equals(Schema?.Type, StringComparison.OrdinalIgnoreCase))
381382
{
382383
if (this.Style == ParameterStyle.Form && this.Explode == true)
383384
{

test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@
4646
"name": "limit",
4747
"description": "maximum number of results to return",
4848
"type": "integer",
49-
"format": "int32",
50-
"collectionFormat": "multi"
49+
"format": "int32"
5150
}
5251
],
5352
"responses": {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32","collectionFormat":"multi"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}
1+
{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}

test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@
4646
"name": "limit",
4747
"description": "maximum number of results to return",
4848
"type": "integer",
49-
"format": "int32",
50-
"collectionFormat": "multi"
49+
"format": "int32"
5150
}
5251
],
5352
"responses": {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32","collectionFormat":"multi"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"$ref":"#/definitions/pet"}}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"$ref":"#/definitions/newPet"}}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}
1+
{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"$ref":"#/definitions/pet"}}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"$ref":"#/definitions/newPet"}}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"format":"int64","type":"integer"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"format":"int32","type":"integer"},"message":{"type":"string"}}}}}

test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

44
using System;
@@ -1356,5 +1356,57 @@ public void CopyConstructorForAdvancedDocumentWorks()
13561356
Assert.Equal(2, doc.Paths.Count);
13571357
Assert.NotNull(doc.Components);
13581358
}
1359+
1360+
[Fact]
1361+
public void SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollectionFormat()
1362+
{
1363+
// Arrange
1364+
var expected = @"swagger: '2.0'
1365+
info: { }
1366+
paths:
1367+
/foo:
1368+
get:
1369+
parameters:
1370+
- in: query
1371+
type: string
1372+
responses: { }";
1373+
1374+
var doc = new OpenApiDocument
1375+
{
1376+
Info = new OpenApiInfo(),
1377+
Paths = new OpenApiPaths
1378+
{
1379+
["/foo"] = new OpenApiPathItem
1380+
{
1381+
Operations = new Dictionary<OperationType, OpenApiOperation>
1382+
{
1383+
[OperationType.Get] = new OpenApiOperation
1384+
{
1385+
Parameters = new List<OpenApiParameter>
1386+
{
1387+
new OpenApiParameter
1388+
{
1389+
In = ParameterLocation.Query,
1390+
Schema = new OpenApiSchema
1391+
{
1392+
Type = "string"
1393+
}
1394+
}
1395+
},
1396+
Responses = new OpenApiResponses()
1397+
}
1398+
}
1399+
}
1400+
}
1401+
};
1402+
1403+
// Act
1404+
var actual = doc.SerializeAsYaml(OpenApiSpecVersion.OpenApi2_0);
1405+
1406+
// Assert
1407+
actual = actual.MakeLineBreaksEnvironmentNeutral();
1408+
expected = expected.MakeLineBreaksEnvironmentNeutral();
1409+
actual.Should().Be(expected);
1410+
}
13591411
}
13601412
}

0 commit comments

Comments
 (0)