diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiPathItemDeserializer.cs index ba5707480..d905ea42e 100644 --- a/src/Microsoft.OpenApi.Readers/V2/OpenApiPathItemDeserializer.cs +++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiPathItemDeserializer.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers.ParseNodes; @@ -32,7 +34,7 @@ internal static partial class OpenApiV2Deserializer { "parameters", (o, n) => { - o.Parameters = n.CreateList(LoadParameter); + LoadPathParameters(o,n); } }, }; @@ -53,5 +55,51 @@ public static OpenApiPathItem LoadPathItem(ParseNode node) return pathItem; } + + private static void LoadPathParameters(OpenApiPathItem pathItem, ParseNode node) + { + node.Context.SetTempStorage(TempStorageKeys.BodyParameter, null); + node.Context.SetTempStorage(TempStorageKeys.FormParameters, null); + + pathItem.Parameters = node.CreateList(LoadParameter); + + // Build request body based on information determined while parsing OpenApiOperation + var bodyParameter = node.Context.GetFromTempStorage(TempStorageKeys.BodyParameter); + if (bodyParameter != null) + { + var requestBody = CreateRequestBody(node.Context, bodyParameter); + foreach(var opPair in pathItem.Operations.Where(x => x.Value.RequestBody is null)) + { + switch (opPair.Key) + { + case OperationType.Post: + case OperationType.Put: + case OperationType.Patch: + opPair.Value.RequestBody = requestBody; + break; + } + } + } + else + { + var formParameters = node.Context.GetFromTempStorage>(TempStorageKeys.FormParameters); + if (formParameters != null) + { + var requestBody = CreateFormBody(node.Context, formParameters); + foreach (var opPair in pathItem.Operations.Where(x => x.Value.RequestBody is null)) + { + switch (opPair.Key) + { + case OperationType.Post: + case OperationType.Put: + case OperationType.Patch: + opPair.Value.RequestBody = requestBody; + break; + } + } + } + } + + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj index e1ec38f8f..c04eb7fd2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj +++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj @@ -14,6 +14,8 @@ + + @@ -85,6 +87,12 @@ Never + + Never + + + Never + Never diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index 5d3331207..a11497cdf 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using FluentAssertions; using Microsoft.OpenApi.Extensions; @@ -253,10 +254,50 @@ public void ParseBasicPathItemWithFormDataShouldSucceed() } // Act - var operation = OpenApiV2Deserializer.LoadPathItem(node); + var pathItem = OpenApiV2Deserializer.LoadPathItem(node); // Assert - operation.Should().BeEquivalentTo(_basicPathItemWithFormData); + pathItem.Should().BeEquivalentTo(_basicPathItemWithFormData); } + + [Fact] + public void ParsePathItemWithFormDataPathParameterShouldSucceed() + { + // Arrange + MapNode node; + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "pathItemWithFormDataPathParameter.yaml"))) + { + node = TestHelper.CreateYamlMapNode(stream); + } + + // Act + var pathItem = OpenApiV2Deserializer.LoadPathItem(node); + + // Assert + // FormData parameters at in the path level are pushed into Operation request bodies. + Assert.True(pathItem.Operations[OperationType.Put].RequestBody != null); + Assert.True(pathItem.Operations[OperationType.Post].RequestBody != null); + Assert.Equal(2, pathItem.Operations.Count(o => o.Value.RequestBody != null)); + } + [Fact] + public void ParsePathItemBodyDataPathParameterShouldSucceed() + { + // Arrange + MapNode node; + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "pathItemWithBodyPathParameter.yaml"))) + { + node = TestHelper.CreateYamlMapNode(stream); + } + + // Act + var pathItem = OpenApiV2Deserializer.LoadPathItem(node); + + // Assert + // FormData parameters at in the path level are pushed into Operation request bodies. + Assert.True(pathItem.Operations[OperationType.Put].RequestBody != null); + Assert.True(pathItem.Operations[OperationType.Post].RequestBody != null); + Assert.Equal(2, pathItem.Operations.Count(o => o.Value.RequestBody != null)); + } + } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithBodyPathParameter.yaml b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithBodyPathParameter.yaml new file mode 100644 index 000000000..c17f4c54e --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithBodyPathParameter.yaml @@ -0,0 +1,31 @@ +put: + summary: Puts a pet in the store with form data + description: "" + responses: + '200': + description: Pet updated. + '405': + description: Invalid input +post: + summary: Posts a pet in the store with form data + description: "" + responses: + '200': + description: Pet updated. +parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: string + - name: name + in: body + description: Updated pet body + required: true + type: object + properties: + name: + type: string + status: + type: string \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithFormDataPathParameter.yaml b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithFormDataPathParameter.yaml new file mode 100644 index 000000000..57178b4ba --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/Samples/OpenApiPathItem/pathItemWithFormDataPathParameter.yaml @@ -0,0 +1,41 @@ +put: + summary: Puts a pet in the store with form data + description: "" + responses: + '200': + description: Pet updated. + '405': + description: Invalid input + x-http-tests: + - parameterValues: + petId: 10 + name: Milo + status: Happy + expectedRequest: + href: /pathitem-form-parameter/10 + headers: + Content-Type: multipart/form-data + content: name=Milo&status=Happy +post: + summary: Posts a pet in the store with form data + description: "" + responses: + '200': + description: Pet updated. +parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: string + - name: name + in: formData + description: Updated name of the pet + required: true + type: string + - name: status + in: formData + description: Updated status of the pet + required: false + type: string