From 06d499abdc232ee5deab967c417e3b971f941286 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Fri, 6 Sep 2024 13:07:12 +0300 Subject: [PATCH 01/10] Check whether the $ref pointer is a locator or identifier and assign the external resource --- .../Reader/V31/OpenApiV31Deserializer.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index a56590bf1..cc9eba030 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -157,9 +157,14 @@ private static (string, string) GetReferenceIdAndExternalResource(string pointer string refId = !pointer.Contains('#') ? pointer : refSegments.Last(); var isExternalResource = !refSegments.First().StartsWith("#"); - string externalResource = isExternalResource - ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" - : null; + string externalResource = null; + if (isExternalResource) + { + if (pointer.Contains('#')) + { + externalResource = $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}"; + } + } return (refId, externalResource); } From 76763ddabd550c62994244935407ef28dc0afd73 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Fri, 6 Sep 2024 13:08:05 +0300 Subject: [PATCH 02/10] Add tests to verify external reference resolution both by $id and $ref locator works --- .../V31Tests/OpenApiDocumentTests.cs | 53 +++++++++++++++++-- .../OpenApiDocument/docWithExternalRef.yaml | 21 ++++++++ .../OpenApiDocument/externalResource.yaml | 22 ++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalResource.yaml diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 2ada8e4bd..bce1ffb68 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -1,15 +1,17 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Threading.Tasks; using FluentAssertions; using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi.Services; using Xunit; +using System.Linq; namespace Microsoft.OpenApi.Readers.Tests.V31Tests { @@ -392,7 +394,7 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 }); var outputWriter = new StringWriter(CultureInfo.InvariantCulture); - var writer = new OpenApiJsonWriter(outputWriter, new() { InlineLocalReferences = true } ); + var writer = new OpenApiJsonWriter(outputWriter, new() { InlineLocalReferences = true }); actual.OpenApiDocument.SerializeAsV31(writer); var serialized = outputWriter.ToString(); } @@ -445,7 +447,7 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() } } }; - + // Serialization var mediaType = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; @@ -461,7 +463,7 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() type: string prop3: type: string"; - + var actualMediaType = mediaType.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1); // Assert @@ -484,5 +486,48 @@ public void ParseDocumentWithReferenceByIdGetsResolved() Assert.Equal("object", requestBodySchema.Type); Assert.Equal("string", parameterSchema.Type); } + + [Fact] + public async Task ExternalDocumentDereferenceToOpenApiDocumentUsingJsonPointerWorks() + { + // Arrange + var path = Path.Combine(Directory.GetCurrentDirectory(), SampleFolderPath); + + var settings = new OpenApiReaderSettings + { + LoadExternalRefs = true, + BaseUrl = new(path), + }; + + // Act + var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExternalRef.yaml"), settings); + var responseSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; + + // Assert + result.OpenApiDocument.Workspace.Contains("./externalResource.yaml"); + responseSchema.Properties.Count.Should().Be(2); // reference has been resolved + } + + [Fact] + public async Task ParseExternalDocumentDereferenceToOpenApiDocumentByIdWorks() + { + // Arrange + var path = Path.Combine(Directory.GetCurrentDirectory(), SampleFolderPath); + + var settings = new OpenApiReaderSettings + { + LoadExternalRefs = true, + BaseUrl = new(path), + }; + + // Act + var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExternalRef.yaml"), settings); + var externalDoc = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "externalResource.yaml"), settings); + + var requestBodySchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Parameters.First().Schema; + + // Assert + requestBodySchema.Properties.Count.Should().Be(2); // reference has been resolved + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml new file mode 100644 index 000000000..7a4b7cd8c --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml @@ -0,0 +1,21 @@ +openapi: 3.1.0 +info: + title: ReferenceById + version: 1.0.0 +paths: + /resource: + get: + parameters: + - name: id + in: query + required: true + schema: + $ref: 'https://example.com/schemas/user.json' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: './externalResource.yaml#/components/schemas/todo' +components: {} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalResource.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalResource.yaml new file mode 100644 index 000000000..78d6c0851 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalResource.yaml @@ -0,0 +1,22 @@ +openapi: 3.1.0 +info: + title: ReferencedById + version: 1.0.0 +paths: {} +components: + schemas: + todo: + type: object + properties: + id: + type: string + name: + type: string + user: + $id: 'https://example.com/schemas/user.json' + type: object + properties: + id: + type: string + name: + type: string \ No newline at end of file From 989c6cf0f928d81b92d8ed9ae33d05a2e7da622b Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 9 Sep 2024 14:53:50 +0300 Subject: [PATCH 03/10] Merge nested if statement --- src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index cc9eba030..d6c9d0fcf 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -158,12 +158,9 @@ private static (string, string) GetReferenceIdAndExternalResource(string pointer var isExternalResource = !refSegments.First().StartsWith("#"); string externalResource = null; - if (isExternalResource) + if (isExternalResource && pointer.Contains('#')) { - if (pointer.Contains('#')) - { - externalResource = $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}"; - } + externalResource = $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}"; } return (refId, externalResource); From 4cbd66d22821ead4a8f4c0a31586e2f61c0ce503 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 23 Sep 2024 13:07:01 +0300 Subject: [PATCH 04/10] code refactor --- .../Services/OpenApiWorkspace.cs | 23 +++++++++++++++++++ .../V31Tests/OpenApiDocumentTests.cs | 7 +++--- .../OpenApiDocument/externalRefById.yaml | 14 +++++++++++ ...Ref.yaml => externalRefByJsonPointer.yaml} | 6 ----- .../PublicApi/PublicApi.approved.txt | 2 ++ 5 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefById.yaml rename test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/{docWithExternalRef.yaml => externalRefByJsonPointer.yaml} (65%) diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 319a5d63f..33bc884b0 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -14,10 +14,22 @@ namespace Microsoft.OpenApi.Services /// public class OpenApiWorkspace { + private Dictionary _documents = new(); private readonly Dictionary _documentsIdRegistry = new(); private readonly Dictionary _artifactsRegistry = new(); private readonly Dictionary _IOpenApiReferenceableRegistry = new(); + /// + /// A list of OpenApiDocuments contained in the workspace + /// + public IEnumerable Documents + { + get + { + return _documents.Values; + } + } + /// /// The base location from where all relative references are resolved /// @@ -96,6 +108,17 @@ public void AddDocumentId(string key, Uri value) } } + /// + /// Add an OpenApiDocument to the workspace. + /// + /// + /// + public void AddDocument(string location, OpenApiDocument document) + { + document.Workspace = this; + _documents.Add(ToLocationUrl(location), document); + } + /// /// Retrieves the document id given a key. /// diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index bce1ffb68..c954387a6 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -500,7 +500,7 @@ public async Task ExternalDocumentDereferenceToOpenApiDocumentUsingJsonPointerWo }; // Act - var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExternalRef.yaml"), settings); + var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "externalRefByJsonPointer.yaml"), settings); var responseSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; // Assert @@ -521,10 +521,11 @@ public async Task ParseExternalDocumentDereferenceToOpenApiDocumentByIdWorks() }; // Act - var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExternalRef.yaml"), settings); - var externalDoc = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "externalResource.yaml"), settings); + var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "externalRefById.yaml"), settings); + var doc2 = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "externalResource.yaml")).OpenApiDocument; var requestBodySchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Parameters.First().Schema; + result.OpenApiDocument.Workspace.RegisterComponents(doc2); // Assert requestBodySchema.Properties.Count.Should().Be(2); // reference has been resolved diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefById.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefById.yaml new file mode 100644 index 000000000..bb3755180 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefById.yaml @@ -0,0 +1,14 @@ +openapi: 3.1.0 +info: + title: ReferenceById + version: 1.0.0 +paths: + /resource: + get: + parameters: + - name: id + in: query + required: true + schema: + $ref: 'https://example.com/schemas/user.json' +components: {} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefByJsonPointer.yaml similarity index 65% rename from test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml rename to test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefByJsonPointer.yaml index 7a4b7cd8c..913b20e7c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithExternalRef.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/externalRefByJsonPointer.yaml @@ -5,12 +5,6 @@ info: paths: /resource: get: - parameters: - - name: id - in: query - required: true - schema: - $ref: 'https://example.com/schemas/user.json' responses: '200': description: OK diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 7eb01a70c..79ab91ecd 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1507,6 +1507,8 @@ namespace Microsoft.OpenApi.Services public OpenApiWorkspace(Microsoft.OpenApi.Services.OpenApiWorkspace workspace) { } public OpenApiWorkspace(System.Uri baseUrl) { } public System.Uri BaseUrl { get; } + public System.Collections.Generic.IEnumerable Documents { get; } + public void AddDocument(string location, Microsoft.OpenApi.Models.OpenApiDocument document) { } public void AddDocumentId(string key, System.Uri value) { } public int ComponentsCount() { } public bool Contains(string location) { } From 4b4d31ddf4ff152417cbd20e76ee630dcf4b181e Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 23 Sep 2024 13:27:58 +0300 Subject: [PATCH 05/10] Make private field readonly --- src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 33bc884b0..3a6183a66 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.Services /// public class OpenApiWorkspace { - private Dictionary _documents = new(); + private readonly Dictionary _documents = new(); private readonly Dictionary _documentsIdRegistry = new(); private readonly Dictionary _artifactsRegistry = new(); private readonly Dictionary _IOpenApiReferenceableRegistry = new(); From 41b3d9db02670dbaf98bd2ccc3dfa91e7a861816 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 1 Oct 2024 19:08:28 +0300 Subject: [PATCH 06/10] code cleanup --- .../Services/OpenApiWorkspace.cs | 23 ------------------- .../PublicApi/PublicApi.approved.txt | 2 -- 2 files changed, 25 deletions(-) diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 3a6183a66..319a5d63f 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -14,22 +14,10 @@ namespace Microsoft.OpenApi.Services /// public class OpenApiWorkspace { - private readonly Dictionary _documents = new(); private readonly Dictionary _documentsIdRegistry = new(); private readonly Dictionary _artifactsRegistry = new(); private readonly Dictionary _IOpenApiReferenceableRegistry = new(); - /// - /// A list of OpenApiDocuments contained in the workspace - /// - public IEnumerable Documents - { - get - { - return _documents.Values; - } - } - /// /// The base location from where all relative references are resolved /// @@ -108,17 +96,6 @@ public void AddDocumentId(string key, Uri value) } } - /// - /// Add an OpenApiDocument to the workspace. - /// - /// - /// - public void AddDocument(string location, OpenApiDocument document) - { - document.Workspace = this; - _documents.Add(ToLocationUrl(location), document); - } - /// /// Retrieves the document id given a key. /// diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 79ab91ecd..7eb01a70c 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1507,8 +1507,6 @@ namespace Microsoft.OpenApi.Services public OpenApiWorkspace(Microsoft.OpenApi.Services.OpenApiWorkspace workspace) { } public OpenApiWorkspace(System.Uri baseUrl) { } public System.Uri BaseUrl { get; } - public System.Collections.Generic.IEnumerable Documents { get; } - public void AddDocument(string location, Microsoft.OpenApi.Models.OpenApiDocument document) { } public void AddDocumentId(string key, System.Uri value) { } public int ComponentsCount() { } public bool Contains(string location) { } From 16ba3b7fe1924034c19769564e59a9da46827696 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 1 Oct 2024 19:46:43 +0300 Subject: [PATCH 07/10] Move method to workspace and remove unnecessary param --- .../Reader/Services/OpenApiWorkspaceLoader.cs | 2 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V3/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V31/OpenApiDocumentDeserializer.cs | 2 +- .../OpenApiComponentsRegistryExtensions.cs | 97 ------------------- .../Services/OpenApiWorkspace.cs | 92 ++++++++++++++++++ .../OpenApiPathItemReferenceTests.cs | 4 +- 7 files changed, 98 insertions(+), 103 deletions(-) delete mode 100644 src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs diff --git a/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs b/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs index 6915d60bd..a3462da70 100644 --- a/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs +++ b/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs @@ -28,7 +28,7 @@ internal async Task LoadAsync(OpenApiReference reference, { _workspace.AddDocumentId(reference.ExternalResource, document.BaseUri); var version = diagnostic?.SpecificationVersion ?? OpenApiSpecVersion.OpenApi3_0; - _workspace.RegisterComponents(document, version); + _workspace.RegisterComponents(document); document.Workspace = _workspace; // Collect remote references by walking document diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index b0e2a29ae..f33d98465 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -252,7 +252,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode) FixRequestBodyReferences(openApiDoc); // Register components - openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi2_0); + openApiDoc.Workspace.RegisterComponents(openApiDoc); return openApiDoc; } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs index 7a17de018..3fcdb9af7 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs @@ -54,7 +54,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode) ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields, openApiDoc); // Register components - openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi3_0); + openApiDoc.Workspace.RegisterComponents(openApiDoc); return openApiDoc; } diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs index b6e0fe5fc..8137fb460 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs @@ -53,7 +53,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode) ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields, openApiDoc); // Register components - openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi3_1); + openApiDoc.Workspace.RegisterComponents(openApiDoc); return openApiDoc; } diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs deleted file mode 100644 index 226853a13..000000000 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Models; - -namespace Microsoft.OpenApi.Services -{ - internal static class OpenApiComponentsRegistryExtensions - { - public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDocument document, OpenApiSpecVersion version = OpenApiSpecVersion.OpenApi3_0) - { - if (document?.Components == null) return; - - string baseUri = document.BaseUri + OpenApiConstants.ComponentsSegment; - string location; - - // Register Schema - foreach (var item in document.Components.Schemas) - { - if (item.Value.Id != null) - { - location = item.Value.Id; - } - else - { - location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; - } - - workspace.RegisterComponent(location, item.Value); - } - - // Register Parameters - foreach (var item in document.Components.Parameters) - { - location = baseUri + ReferenceType.Parameter.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register Responses - foreach (var item in document.Components.Responses) - { - location = baseUri + ReferenceType.Response.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register RequestBodies - foreach (var item in document.Components.RequestBodies) - { - location = baseUri + ReferenceType.RequestBody.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register Links - foreach (var item in document.Components.Links) - { - location = baseUri + ReferenceType.Link.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register Callbacks - foreach (var item in document.Components.Callbacks) - { - location = baseUri + ReferenceType.Callback.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register PathItems - foreach (var item in document.Components.PathItems) - { - location = baseUri + ReferenceType.PathItem.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register Examples - foreach (var item in document.Components.Examples) - { - location = baseUri + ReferenceType.Example.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register Headers - foreach (var item in document.Components.Headers) - { - location = baseUri + ReferenceType.Header.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - - // Register SecuritySchemes - foreach (var item in document.Components.SecuritySchemes) - { - location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key; - workspace.RegisterComponent(location, item.Value); - } - } - } -} diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 319a5d63f..66cc7b881 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -54,6 +55,97 @@ public int ComponentsCount() return _IOpenApiReferenceableRegistry.Count + _artifactsRegistry.Count; } + /// + /// Registers a document's components into the workspace + /// + /// + public void RegisterComponents(OpenApiDocument document) + { + if (document?.Components == null) return; + + string baseUri = document.BaseUri + OpenApiConstants.ComponentsSegment; + string location; + + // Register Schema + foreach (var item in document.Components.Schemas) + { + if (item.Value.Id != null) + { + location = item.Value.Id; + } + else + { + location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; + } + + RegisterComponent(location, item.Value); + } + + // Register Parameters + foreach (var item in document.Components.Parameters) + { + location = baseUri + ReferenceType.Parameter.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register Responses + foreach (var item in document.Components.Responses) + { + location = baseUri + ReferenceType.Response.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register RequestBodies + foreach (var item in document.Components.RequestBodies) + { + location = baseUri + ReferenceType.RequestBody.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register Links + foreach (var item in document.Components.Links) + { + location = baseUri + ReferenceType.Link.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register Callbacks + foreach (var item in document.Components.Callbacks) + { + location = baseUri + ReferenceType.Callback.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register PathItems + foreach (var item in document.Components.PathItems) + { + location = baseUri + ReferenceType.PathItem.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register Examples + foreach (var item in document.Components.Examples) + { + location = baseUri + ReferenceType.Example.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register Headers + foreach (var item in document.Components.Headers) + { + location = baseUri + ReferenceType.Header.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + + // Register SecuritySchemes + foreach (var item in document.Components.SecuritySchemes) + { + location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key; + RegisterComponent(location, item.Value); + } + } + + /// /// Registers a component in the component registry. /// diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs index ec532bed7..2d7354f78 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs @@ -83,8 +83,8 @@ public OpenApiPathItemReferenceTests() _openApiDoc = OpenApiDocument.Parse(OpenApi, OpenApiConstants.Yaml).OpenApiDocument; _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, OpenApiConstants.Yaml).OpenApiDocument; _openApiDoc.Workspace.AddDocumentId("https://myserver.com/beta", _openApiDoc_2.BaseUri); - _openApiDoc.Workspace.RegisterComponents(_openApiDoc_2, OpenApiSpecVersion.OpenApi3_1); - _openApiDoc_2.Workspace.RegisterComponents(_openApiDoc_2, OpenApiSpecVersion.OpenApi3_1); + _openApiDoc.Workspace.RegisterComponents(_openApiDoc_2); + _openApiDoc_2.Workspace.RegisterComponents(_openApiDoc_2); _localPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc_2) { From 983c5766754fb93ac5526ea2f3359339e2d6c804 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 1 Oct 2024 19:46:54 +0300 Subject: [PATCH 08/10] Update XML comment --- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 5fee30ac2..f04f47680 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -24,7 +24,7 @@ namespace Microsoft.OpenApi.Models public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible { /// - /// Related workspace containing OpenApiDocuments that are referenced in this document + /// Related workspace containing components that are referenced in a document /// public OpenApiWorkspace Workspace { get; set; } From 74d88665e9e9c8afbe4e7a802935005ce3e9e921 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 1 Oct 2024 19:47:04 +0300 Subject: [PATCH 09/10] Update public API --- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 7eb01a70c..00b16a254 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1512,6 +1512,7 @@ namespace Microsoft.OpenApi.Services public bool Contains(string location) { } public System.Uri GetDocumentId(string key) { } public bool RegisterComponent(string location, T component) { } + public void RegisterComponents(Microsoft.OpenApi.Models.OpenApiDocument document) { } public T ResolveReference(string location) { } } public class OperationSearch : Microsoft.OpenApi.Services.OpenApiVisitorBase From a60b992a341397daedacb5ddbcf9fff35fb06d36 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 1 Oct 2024 19:52:42 +0300 Subject: [PATCH 10/10] Use null coalesce ?? operator --- src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 66cc7b881..7652ed242 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -69,14 +69,7 @@ public void RegisterComponents(OpenApiDocument document) // Register Schema foreach (var item in document.Components.Schemas) { - if (item.Value.Id != null) - { - location = item.Value.Id; - } - else - { - location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; - } + location = item.Value.Id ?? baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; RegisterComponent(location, item.Value); }