Skip to content

Commit 05b9baf

Browse files
authored
Merge pull request #922 from /issues/885
Add support for request body path parameters in v2
2 parents 68f4ec0 + d4b2c7b commit 05b9baf

File tree

5 files changed

+172
-3
lines changed

5 files changed

+172
-3
lines changed

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

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

4+
using System.Collections.Generic;
5+
using System.Linq;
46
using Microsoft.OpenApi.Extensions;
57
using Microsoft.OpenApi.Models;
68
using Microsoft.OpenApi.Readers.ParseNodes;
@@ -32,7 +34,7 @@ internal static partial class OpenApiV2Deserializer
3234
{
3335
"parameters", (o, n) =>
3436
{
35-
o.Parameters = n.CreateList(LoadParameter);
37+
LoadPathParameters(o,n);
3638
}
3739
},
3840
};
@@ -53,5 +55,51 @@ public static OpenApiPathItem LoadPathItem(ParseNode node)
5355

5456
return pathItem;
5557
}
58+
59+
private static void LoadPathParameters(OpenApiPathItem pathItem, ParseNode node)
60+
{
61+
node.Context.SetTempStorage(TempStorageKeys.BodyParameter, null);
62+
node.Context.SetTempStorage(TempStorageKeys.FormParameters, null);
63+
64+
pathItem.Parameters = node.CreateList(LoadParameter);
65+
66+
// Build request body based on information determined while parsing OpenApiOperation
67+
var bodyParameter = node.Context.GetFromTempStorage<OpenApiParameter>(TempStorageKeys.BodyParameter);
68+
if (bodyParameter != null)
69+
{
70+
var requestBody = CreateRequestBody(node.Context, bodyParameter);
71+
foreach(var opPair in pathItem.Operations.Where(x => x.Value.RequestBody is null))
72+
{
73+
switch (opPair.Key)
74+
{
75+
case OperationType.Post:
76+
case OperationType.Put:
77+
case OperationType.Patch:
78+
opPair.Value.RequestBody = requestBody;
79+
break;
80+
}
81+
}
82+
}
83+
else
84+
{
85+
var formParameters = node.Context.GetFromTempStorage<List<OpenApiParameter>>(TempStorageKeys.FormParameters);
86+
if (formParameters != null)
87+
{
88+
var requestBody = CreateFormBody(node.Context, formParameters);
89+
foreach (var opPair in pathItem.Operations.Where(x => x.Value.RequestBody is null))
90+
{
91+
switch (opPair.Key)
92+
{
93+
case OperationType.Post:
94+
case OperationType.Put:
95+
case OperationType.Patch:
96+
opPair.Value.RequestBody = requestBody;
97+
break;
98+
}
99+
}
100+
}
101+
}
102+
103+
}
56104
}
57105
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
</PropertyGroup>
1515
<ItemGroup>
1616
<None Remove="V2Tests\Samples\ComponentRootReference.json" />
17+
<None Remove="V2Tests\Samples\OpenApiPathItem\pathItemWithBodyPathParameter.yaml" />
18+
<None Remove="V2Tests\Samples\OpenApiPathItem\pathItemWithFormDataPathParameter.yaml" />
1719
<None Remove="V3Tests\Samples\OpenApiWorkspace\TodoComponents.yaml" />
1820
<None Remove="V3Tests\Samples\OpenApiWorkspace\TodoMain.yaml" />
1921
</ItemGroup>
@@ -85,6 +87,12 @@
8587
<EmbeddedResource Include="V2Tests\Samples\OpenApiParameter\queryParameter.yaml">
8688
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
8789
</EmbeddedResource>
90+
<EmbeddedResource Include="V2Tests\Samples\OpenApiPathItem\pathItemWithFormDataPathParameter.yaml">
91+
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
92+
</EmbeddedResource>
93+
<EmbeddedResource Include="V2Tests\Samples\OpenApiPathItem\pathItemWithBodyPathParameter.yaml">
94+
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
95+
</EmbeddedResource>
8896
<EmbeddedResource Include="V2Tests\Samples\OpenApiPathItem\basicPathItemWithFormData.yaml">
8997
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
9098
</EmbeddedResource>

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

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.IO;
6+
using System.Linq;
67
using System.Text;
78
using FluentAssertions;
89
using Microsoft.OpenApi.Extensions;
@@ -253,10 +254,50 @@ public void ParseBasicPathItemWithFormDataShouldSucceed()
253254
}
254255

255256
// Act
256-
var operation = OpenApiV2Deserializer.LoadPathItem(node);
257+
var pathItem = OpenApiV2Deserializer.LoadPathItem(node);
257258

258259
// Assert
259-
operation.Should().BeEquivalentTo(_basicPathItemWithFormData);
260+
pathItem.Should().BeEquivalentTo(_basicPathItemWithFormData);
260261
}
262+
263+
[Fact]
264+
public void ParsePathItemWithFormDataPathParameterShouldSucceed()
265+
{
266+
// Arrange
267+
MapNode node;
268+
using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "pathItemWithFormDataPathParameter.yaml")))
269+
{
270+
node = TestHelper.CreateYamlMapNode(stream);
271+
}
272+
273+
// Act
274+
var pathItem = OpenApiV2Deserializer.LoadPathItem(node);
275+
276+
// Assert
277+
// FormData parameters at in the path level are pushed into Operation request bodies.
278+
Assert.True(pathItem.Operations[OperationType.Put].RequestBody != null);
279+
Assert.True(pathItem.Operations[OperationType.Post].RequestBody != null);
280+
Assert.Equal(2, pathItem.Operations.Count(o => o.Value.RequestBody != null));
281+
}
282+
[Fact]
283+
public void ParsePathItemBodyDataPathParameterShouldSucceed()
284+
{
285+
// Arrange
286+
MapNode node;
287+
using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "pathItemWithBodyPathParameter.yaml")))
288+
{
289+
node = TestHelper.CreateYamlMapNode(stream);
290+
}
291+
292+
// Act
293+
var pathItem = OpenApiV2Deserializer.LoadPathItem(node);
294+
295+
// Assert
296+
// FormData parameters at in the path level are pushed into Operation request bodies.
297+
Assert.True(pathItem.Operations[OperationType.Put].RequestBody != null);
298+
Assert.True(pathItem.Operations[OperationType.Post].RequestBody != null);
299+
Assert.Equal(2, pathItem.Operations.Count(o => o.Value.RequestBody != null));
300+
}
301+
261302
}
262303
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
put:
2+
summary: Puts a pet in the store with form data
3+
description: ""
4+
responses:
5+
'200':
6+
description: Pet updated.
7+
'405':
8+
description: Invalid input
9+
post:
10+
summary: Posts a pet in the store with form data
11+
description: ""
12+
responses:
13+
'200':
14+
description: Pet updated.
15+
parameters:
16+
- name: petId
17+
in: path
18+
description: ID of pet that needs to be updated
19+
required: true
20+
schema:
21+
type: string
22+
- name: name
23+
in: body
24+
description: Updated pet body
25+
required: true
26+
type: object
27+
properties:
28+
name:
29+
type: string
30+
status:
31+
type: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
put:
2+
summary: Puts a pet in the store with form data
3+
description: ""
4+
responses:
5+
'200':
6+
description: Pet updated.
7+
'405':
8+
description: Invalid input
9+
x-http-tests:
10+
- parameterValues:
11+
petId: 10
12+
name: Milo
13+
status: Happy
14+
expectedRequest:
15+
href: /pathitem-form-parameter/10
16+
headers:
17+
Content-Type: multipart/form-data
18+
content: name=Milo&status=Happy
19+
post:
20+
summary: Posts a pet in the store with form data
21+
description: ""
22+
responses:
23+
'200':
24+
description: Pet updated.
25+
parameters:
26+
- name: petId
27+
in: path
28+
description: ID of pet that needs to be updated
29+
required: true
30+
schema:
31+
type: string
32+
- name: name
33+
in: formData
34+
description: Updated name of the pet
35+
required: true
36+
type: string
37+
- name: status
38+
in: formData
39+
description: Updated status of the pet
40+
required: false
41+
type: string

0 commit comments

Comments
 (0)