Skip to content

Commit 8299ed0

Browse files
authored
Merge pull request #398 from VitaliyKurokhtin/vvk/multiple-responses-produces-fix
Fix to properly assign schemas to content of all media types of all r…
2 parents c08eb18 + 73a457b commit 8299ed0

File tree

6 files changed

+218
-66
lines changed

6 files changed

+218
-66
lines changed

src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ internal static OpenApiOperation LoadOperation(ParseNode node)
136136
ProcessProduces(node.CheckMapNode("responses"), response, node.Context);
137137
}
138138

139+
// Reset so that it's not picked up later
140+
node.Context.SetTempStorage(TempStorageKeys.OperationProduces, null);
141+
139142
return operation;
140143
}
141144

src/Microsoft.OpenApi.Readers/V2/OpenApiResponseDeserializer.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,35 +63,39 @@ internal static partial class OpenApiV2Deserializer
6363
private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, ParsingContext context)
6464
{
6565
var produces = context.GetFromTempStorage<List<string>>(TempStorageKeys.OperationProduces) ??
66-
context.GetFromTempStorage<List<string>>(TempStorageKeys.GlobalProduces) ?? new List<string>();
66+
context.GetFromTempStorage<List<string>>(TempStorageKeys.GlobalProduces);
6767

6868
if (response.Content == null)
6969
{
7070
response.Content = new Dictionary<string, OpenApiMediaType>();
7171
}
7272

73-
foreach (var produce in produces)
73+
if (produces != null)
7474
{
75-
var schema = context.GetFromTempStorage<OpenApiSchema>(TempStorageKeys.ResponseSchema, response);
76-
context.SetTempStorage(TempStorageKeys.ResponseSchema, null, response);
77-
78-
if (response.Content.ContainsKey(produce) && response.Content[produce] != null)
75+
foreach (var produce in produces)
7976
{
80-
if (schema != null)
77+
var schema = context.GetFromTempStorage<OpenApiSchema>(TempStorageKeys.ResponseSchema, response);
78+
79+
if (response.Content.ContainsKey(produce) && response.Content[produce] != null)
8180
{
82-
response.Content[produce].Schema = schema;
83-
ProcessAnyFields(mapNode, response.Content[produce], _mediaTypeAnyFields);
81+
if (schema != null)
82+
{
83+
response.Content[produce].Schema = schema;
84+
ProcessAnyFields(mapNode, response.Content[produce], _mediaTypeAnyFields);
85+
}
8486
}
85-
}
86-
else
87-
{
88-
var mediaType = new OpenApiMediaType
87+
else
8988
{
90-
Schema = schema
91-
};
89+
var mediaType = new OpenApiMediaType
90+
{
91+
Schema = schema
92+
};
9293

93-
response.Content.Add(produce, mediaType);
94+
response.Content.Add(produce, mediaType);
95+
}
9496
}
97+
98+
context.SetTempStorage(TempStorageKeys.ResponseSchema, null, response);
9599
}
96100
}
97101

test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@
9797
<EmbeddedResource Include="V2Tests\Samples\OpenApiSecurityScheme\oauth2PasswordSecurityScheme.yaml">
9898
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
9999
</EmbeddedResource>
100+
<EmbeddedResource Include="V2Tests\Samples\multipleProduces.json">
101+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
102+
</EmbeddedResource>
100103
<EmbeddedResource Include="V2Tests\Samples\twoResponses.json">
101104
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
102105
</EmbeddedResource>

test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs

Lines changed: 126 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -158,25 +158,12 @@ public void ShouldParseProducesInAnyOrder()
158158
Assert.NotNull(doc.Paths["/items"]);
159159
Assert.Equal(3, doc.Paths["/items"].Operations.Count);
160160

161-
foreach (var operation in doc.Paths["/items"].Operations)
161+
var successSchema = new OpenApiSchema()
162162
{
163-
Assert.Equal(2, operation.Value.Responses.Count);
164-
165-
var okResponse = operation.Value.Responses["200"];
166-
okResponse.ShouldBeEquivalentTo(
167-
new OpenApiResponse()
168-
{
169-
Description = "An OK response",
170-
Content =
171-
{
172-
["application/json"] = new OpenApiMediaType()
173-
{
174-
Schema = new OpenApiSchema()
175-
{
176-
Type = "array",
177-
Items = new OpenApiSchema()
178-
{
179-
Properties = new Dictionary<string, OpenApiSchema>()
163+
Type = "array",
164+
Items = new OpenApiSchema()
165+
{
166+
Properties = new Dictionary<string, OpenApiSchema>()
180167
{
181168
{ "id", new OpenApiSchema()
182169
{
@@ -185,29 +172,17 @@ public void ShouldParseProducesInAnyOrder()
185172
}
186173
}
187174
},
188-
Reference = new OpenApiReference()
189-
{
190-
Type = ReferenceType.Schema,
191-
Id = "Item"
192-
}
193-
}
194-
},
195-
}
196-
}
197-
});
198-
199-
var errorResponse = operation.Value.Responses["default"];
200-
errorResponse.ShouldBeEquivalentTo(
201-
new OpenApiResponse()
175+
Reference = new OpenApiReference()
202176
{
203-
Description = "An error response",
204-
Content =
205-
{
206-
["application/json"] = new OpenApiMediaType()
207-
{
208-
Schema = new OpenApiSchema()
209-
{
210-
Properties = new Dictionary<string, OpenApiSchema>()
177+
Type = ReferenceType.Schema,
178+
Id = "Item"
179+
}
180+
}
181+
};
182+
183+
var errorSchema = new OpenApiSchema()
184+
{
185+
Properties = new Dictionary<string, OpenApiSchema>()
211186
{
212187
{ "code", new OpenApiSchema()
213188
{
@@ -226,17 +201,120 @@ public void ShouldParseProducesInAnyOrder()
226201
}
227202
}
228203
},
229-
Reference = new OpenApiReference()
230-
{
231-
Type = ReferenceType.Schema,
232-
Id = "Error"
233-
}
234-
},
235-
}
236-
}
204+
Reference = new OpenApiReference()
205+
{
206+
Type = ReferenceType.Schema,
207+
Id = "Error"
208+
}
209+
};
210+
211+
foreach (var operation in doc.Paths["/items"].Operations)
212+
{
213+
Assert.Equal(2, operation.Value.Responses.Count);
214+
215+
var okResponse = operation.Value.Responses["200"];
216+
okResponse.ShouldBeEquivalentTo(
217+
new OpenApiResponse()
218+
{
219+
Description = "An OK response",
220+
Content = GetMediaTypes(successSchema, operation.Key != OperationType.Post)
237221
});
222+
223+
var errorResponse = operation.Value.Responses["default"];
224+
errorResponse.ShouldBeEquivalentTo(
225+
new OpenApiResponse()
226+
{
227+
Description = "An error response",
228+
Content = GetMediaTypes(errorSchema, operation.Key != OperationType.Post)
229+
});
230+
}
231+
232+
IDictionary<string, OpenApiMediaType> GetMediaTypes(OpenApiSchema schema, bool includeXml)
233+
{
234+
var mediaTypes = new Dictionary<string, OpenApiMediaType>
235+
{
236+
["application/json"] = new OpenApiMediaType() { Schema = schema }
237+
};
238+
if (includeXml)
239+
{
240+
mediaTypes["application/xml"] = new OpenApiMediaType() { Schema = schema };
241+
}
242+
return mediaTypes;
238243
}
239244
}
240245
}
246+
247+
[Fact]
248+
public void ShouldAssignSchemaToAllResponses()
249+
{
250+
OpenApiDocument document;
251+
OpenApiDiagnostic diagnostic;
252+
using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "multipleProduces.json")))
253+
{
254+
document = new OpenApiStreamReader().Read(stream, out diagnostic);
255+
}
256+
257+
Assert.Equal(OpenApiSpecVersion.OpenApi2_0, diagnostic.SpecificationVersion);
258+
259+
var successSchema = new OpenApiSchema
260+
{
261+
Type = "array",
262+
Items = new OpenApiSchema
263+
{
264+
Properties = {
265+
{ "id", new OpenApiSchema
266+
{
267+
Type = "string",
268+
Description = "Item identifier."
269+
}
270+
}
271+
},
272+
Reference = new OpenApiReference
273+
{
274+
Id = "Item",
275+
Type = ReferenceType.Schema
276+
}
277+
}
278+
};
279+
var errorSchema = new OpenApiSchema
280+
{
281+
Properties = {
282+
{ "code", new OpenApiSchema
283+
{
284+
Type = "integer",
285+
Format = "int32"
286+
}
287+
},
288+
{ "message", new OpenApiSchema
289+
{
290+
Type = "string"
291+
}
292+
},
293+
{ "fields", new OpenApiSchema
294+
{
295+
Type = "string"
296+
}
297+
}
298+
},
299+
Reference = new OpenApiReference
300+
{
301+
Id = "Error",
302+
Type = ReferenceType.Schema
303+
}
304+
};
305+
var responses = document.Paths["/items"].Operations[OperationType.Get].Responses;
306+
foreach (var response in responses)
307+
{
308+
var targetSchema = response.Key == "200" ? successSchema : errorSchema;
309+
310+
var json = response.Value.Content["application/json"];
311+
Assert.NotNull(json);
312+
json.Schema.ShouldBeEquivalentTo(targetSchema);
313+
314+
var xml = response.Value.Content["application/xml"];
315+
Assert.NotNull(xml);
316+
xml.Schema.ShouldBeEquivalentTo(targetSchema);
317+
}
318+
}
241319
}
242320
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"swagger": "2.0",
3+
"info": {
4+
"title": "Multiple produces",
5+
"version": "1.0.0"
6+
},
7+
"schemes": [
8+
"https"
9+
],
10+
"basePath": "/",
11+
"paths": {
12+
"/items": {
13+
"get": {
14+
"produces": [
15+
"application/json",
16+
"application/xml"
17+
],
18+
"responses": {
19+
"200": {
20+
"description": "An OK response",
21+
"schema": {
22+
"type": "array",
23+
"items": {
24+
"$ref": "#/definitions/Item"
25+
}
26+
}
27+
},
28+
"default": {
29+
"description": "An error response",
30+
"schema": {
31+
"$ref": "#/definitions/Error"
32+
}
33+
}
34+
}
35+
}
36+
}
37+
},
38+
"definitions": {
39+
"Item": {
40+
"properties": {
41+
"id": {
42+
"type": "string",
43+
"description": "Item identifier."
44+
}
45+
}
46+
},
47+
"Error": {
48+
"properties": {
49+
"code": {
50+
"type": "integer",
51+
"format": "int32"
52+
},
53+
"message": {
54+
"type": "string"
55+
},
56+
"fields": {
57+
"type": "string"
58+
}
59+
}
60+
}
61+
}
62+
}

test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/twoResponses.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"/items": {
1313
"get": {
1414
"produces": [
15-
"application/json"
15+
"application/json",
16+
"application/xml"
1617
],
1718
"responses": {
1819
"200": {
@@ -70,7 +71,8 @@
7071
}
7172
},
7273
"produces": [
73-
"application/json"
74+
"application/json",
75+
"application/xml"
7476
]
7577
}
7678
}

0 commit comments

Comments
 (0)