diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj index cc663fc98..c7d1cb30e 100644 --- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj +++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj @@ -10,7 +10,7 @@ Microsoft Microsoft.OpenApi.Readers Microsoft.OpenApi.Readers - 1.2.1 + 1.2.3 OpenAPI.NET Readers for JSON and YAML documents © Microsoft Corporation. All rights reserved. OpenAPI .NET diff --git a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs index 107454796..c05456cec 100644 --- a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs +++ b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs @@ -45,7 +45,7 @@ public OpenApiDocument Read(TextReader input, out OpenApiDiagnostic diagnostic) catch (YamlException ex) { diagnostic = new OpenApiDiagnostic(); - diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message)); + diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message)); return new OpenApiDocument(); } diff --git a/src/Microsoft.OpenApi.Readers/Services/OpenApiReferenceResolver.cs b/src/Microsoft.OpenApi.Readers/Services/OpenApiReferenceResolver.cs index c6ebe24b3..033a94500 100644 --- a/src/Microsoft.OpenApi.Readers/Services/OpenApiReferenceResolver.cs +++ b/src/Microsoft.OpenApi.Readers/Services/OpenApiReferenceResolver.cs @@ -52,6 +52,7 @@ public override void Visit(OpenApiComponents components) ResolveMap(components.Examples); ResolveMap(components.Schemas); ResolveMap(components.SecuritySchemes); + ResolveMap(components.Headers); } public override void Visit(IDictionary callbacks) @@ -99,6 +100,15 @@ public override void Visit(OpenApiResponses responses) ResolveMap(responses); } + /// + /// Resolve all references to headers + /// + /// + public override void Visit(IDictionary headers) + { + ResolveMap(headers); + } + /// /// Resolve all references to SecuritySchemes /// diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs index 785ed6ee7..45d076370 100644 --- a/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers.ParseNodes; @@ -164,6 +165,7 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List(formParameters.Where(p => p.Required).Select(p => p.Name)) @@ -201,9 +203,11 @@ internal static OpenApiRequestBody CreateRequestBody( v => new OpenApiMediaType { Schema = bodyParameter.Schema - }) + }), + Extensions = bodyParameter.Extensions }; + requestBody.Extensions[OpenApiConstants.BodyName] = new OpenApiString(bodyParameter.Name); return requestBody; } diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj index 8b5c990c1..c894aeb5a 100644 --- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj +++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj @@ -10,7 +10,7 @@ Microsoft Microsoft.OpenApi Microsoft.OpenApi - 1.2.1 + 1.2.3 .NET models with JSON and YAML writers for OpenAPI specification © Microsoft Corporation. All rights reserved. OpenAPI .NET diff --git a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs index 11e6d8f70..3a29a88b1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs @@ -560,6 +560,11 @@ public static class OpenApiConstants /// public const string DefaultDescription = "Default Description"; + /// + /// Field: BodyName extensions + /// + public const string BodyName = "x-bodyName"; + /// /// Field: version3_0_0 /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 9e1a2ae5d..f17f81328 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -228,6 +228,12 @@ public void SerializeAsV2(IOpenApiWriter writer) { foreach (var property in RequestBody.Content.First().Value.Schema.Properties) { + var paramName = property.Key; + var paramSchema = property.Value; + if (paramSchema.Type == "string" && paramSchema.Format == "binary") { + paramSchema.Type = "file"; + paramSchema.Format = null; + } parameters.Add( new OpenApiFormDataParameter { @@ -235,23 +241,31 @@ public void SerializeAsV2(IOpenApiWriter writer) Name = property.Key, Schema = property.Value, Required = RequestBody.Content.First().Value.Schema.Required.Contains(property.Key) + }); } } else { var content = RequestBody.Content.Values.FirstOrDefault(); + var bodyParameter = new OpenApiBodyParameter { Description = RequestBody.Description, // V2 spec actually allows the body to have custom name. - // Our library does not support this at the moment. + // To allow round-tripping we use an extension to hold the name Name = "body", Schema = content?.Schema ?? new OpenApiSchema(), Required = RequestBody.Required, - Extensions = RequestBody.Extensions + Extensions = RequestBody.Extensions.ToDictionary(k => k.Key, v => v.Value) // Clone extensions so we can remove the x-bodyName extensions from the output V2 model. }; + if (bodyParameter.Extensions.ContainsKey(OpenApiConstants.BodyName)) + { + bodyParameter.Name = (RequestBody.Extensions[OpenApiConstants.BodyName] as OpenApiString)?.Value ?? "body"; + bodyParameter.Extensions.Remove(OpenApiConstants.BodyName); + } + parameters.Add(bodyParameter); } } 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 7866a1d63..a4b588599 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj +++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj @@ -150,6 +150,7 @@ Never + Never diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index 83620aa29..0deb72a5c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -7,6 +7,7 @@ using FluentAssertions; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers.ParseNodes; using Microsoft.OpenApi.Readers.V2; @@ -180,6 +181,9 @@ public class OpenApiOperationTests Type = "object" } } + }, + Extensions = { + [OpenApiConstants.BodyName] = new OpenApiString("petObject") } }, Responses = new OpenApiResponses diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiResponseTests.cs new file mode 100644 index 000000000..60e3db6e4 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiResponseTests.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.IO; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Readers.ParseNodes; +using Microsoft.OpenApi.Readers.V3; +using Xunit; + +namespace Microsoft.OpenApi.Readers.Tests.V3Tests +{ + [Collection("DefaultSettings")] + public class OpenApiResponseTests + { + private const string SampleFolderPath = "V3Tests/Samples/OpenApiResponse/"; + + [Fact] + public void ResponseWithReferencedHeaderShouldReferenceComponent() + { + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "responseWithHeaderReference.yaml"))) + { + var openApiDoc = new OpenApiStreamReader().Read(stream, out var diagnostic); + + var response = openApiDoc.Components.Responses["Test"]; + + Assert.Same(response.Headers.First().Value, openApiDoc.Components.Headers.First().Value); + } + } + } +} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiResponse/responseWithHeaderReference.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiResponse/responseWithHeaderReference.yaml new file mode 100644 index 000000000..f2394282e --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiResponse/responseWithHeaderReference.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.0 +info: + title: Example of response referencing a header + version: 1.0.0 +components: + headers: + X-Test: + description: Test + schema: + type: string + responses: + Test: + description: Test Repsonse + headers: + X-Test: + $ref: '#/components/headers/X-Test' \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 2053a37d8..1a8ea432a 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1,4 +1,4 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"Microsoft.OpenApi.Readers.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100957cb48387b2a5f54f5ce39255f18f26d32a39990db27cf48737afc6bc62759ba996b8a2bfb675d4e39f3d06ecb55a178b1b4031dcb2a767e29977d88cce864a0d16bfc1b3bebb0edf9fe285f10fffc0a85f93d664fa05af07faa3aad2e545182dbf787e3fd32b56aca95df1a3c4e75dec164a3f1a4c653d971b01ffc39eb3c4")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"Microsoft.OpenApi.Readers.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100957cb48387b2a5f54f5ce39255f18f26d32a39990db27cf48737afc6bc62759ba996b8a2bfb675d4e39f3d06ecb55a178b1b4031dcb2a767e29977d88cce864a0d16bfc1b3bebb0edf9fe285f10fffc0a85f93d664fa05af07faa3aad2e545182dbf787e3fd32b56aca95df1a3c4e75dec164a3f1a4c653d971b01ffc39eb3c4")] [assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"Microsoft.OpenApi.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100957cb48387b2a5f54f5ce39255f18f26d32a39990db27cf48737afc6bc62759ba996b8a2bfb675d4e39f3d06ecb55a178b1b4031dcb2a767e29977d88cce864a0d16bfc1b3bebb0edf9fe285f10fffc0a85f93d664fa05af07faa3aad2e545182dbf787e3fd32b56aca95df1a3c4e75dec164a3f1a4c653d971b01ffc39eb3c4")] [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6", FrameworkDisplayName=".NET Framework 4.6")] namespace Microsoft.OpenApi.Any @@ -352,6 +352,7 @@ namespace Microsoft.OpenApi.Models public const string BasePath = "basePath"; public const string Basic = "basic"; public const string BearerFormat = "bearerFormat"; + public const string BodyName = "x-bodyName"; public const string Callbacks = "callbacks"; public const string ClientCredentials = "clientCredentials"; public const string Components = "components";