Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Microsoft.OpenApi/Models/OpenApiConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,11 @@ public static class OpenApiConstants
/// </summary>
public const string BaseRegistryUri = "https://openapi.net/";

/// <summary>
/// The components path segment in a $ref value.
/// </summary>
public const string ComponentsSegment = "/components/";

#region V2.0

/// <summary>
Expand Down
24 changes: 12 additions & 12 deletions src/Microsoft.OpenApi/Models/OpenApiDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,22 +483,22 @@ public IOpenApiReferenceable ResolveReference(OpenApiReference reference)
/// <param name="referenceUri"></param>
/// <returns>A JsonSchema ref.</returns>
public JsonSchema ResolveJsonSchemaReference(Uri referenceUri)
{
{
const char pound = '#';
string uriLocation;
string id = referenceUri.OriginalString.Split('/')?.Last();
string relativePath = "/components/" + ReferenceType.Schema.GetDisplayName() + "/" + id;

if (referenceUri.OriginalString.StartsWith("#"))
int poundIndex = referenceUri.OriginalString.IndexOf(pound);

if (poundIndex > 0)
{
// Local reference
uriLocation = BaseUri + relativePath;
// External reference, ex: ./TodoReference.yaml#/components/schemas/todo
string externalUri = referenceUri.OriginalString.Split(pound).First();
Uri externalDocId = Workspace.GetDocumentId(externalUri);
string relativePath = referenceUri.OriginalString.Split(pound).Last();
uriLocation = externalDocId + relativePath;
}
else
{
// External reference
var externalUri = referenceUri.OriginalString.Split('#').First();
var externalDocId = Workspace.GetDocumentId(externalUri);
uriLocation = externalDocId + relativePath;
uriLocation = BaseUri + referenceUri.ToString().TrimStart(pound);
}

return (JsonSchema)Workspace.ResolveReference<IBaseDocument>(uriLocation);
Expand Down Expand Up @@ -569,7 +569,7 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool
}

string uriLocation;
string relativePath = "/components/" + reference.Type.GetDisplayName() + "/" + reference.Id;
string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id;

uriLocation = useExternal
? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.OpenApi.Interfaces;
Expand Down Expand Up @@ -27,15 +27,16 @@ internal async Task<OpenApiDiagnostic> LoadAsync(OpenApiReference reference,
CancellationToken cancellationToken = default)
{
_workspace.AddDocumentId(reference.ExternalResource, document.BaseUri);
_workspace.RegisterComponents(document);
var version = diagnostic?.SpecificationVersion ?? OpenApiSpecVersion.OpenApi3_0;
_workspace.RegisterComponents(document, version);
document.Workspace = _workspace;

// Collect remote references by walking document
var referenceCollector = new OpenApiRemoteReferenceCollector();
var collectorWalker = new OpenApiWalker(referenceCollector);
collectorWalker.Walk(document);

diagnostic ??= new();
diagnostic ??= new() { SpecificationVersion = version };

// Walk references
foreach (var item in referenceCollector.References)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode)
FixRequestBodyReferences(openApiDoc);

// Register components
openApiDoc.Workspace.RegisterComponents(openApiDoc);
openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi2_0);

return openApiDoc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode)
ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields);

// Register components
openApiDoc.Workspace.RegisterComponents(openApiDoc);
openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi3_0);

return openApiDoc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static OpenApiDocument LoadOpenApi(RootNode rootNode)
ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields);

// Register components
openApiDoc.Workspace.RegisterComponents(openApiDoc);
openApiDoc.Workspace.RegisterComponents(openApiDoc, OpenApiSpecVersion.OpenApi3_1);

return openApiDoc;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,86 +1,98 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using Json.Schema;
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)
public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDocument document, OpenApiSpecVersion version = OpenApiSpecVersion.OpenApi3_0)
{
if (document?.Components == null) return;

var baseUri = document.BaseUri + "/components/";
string baseUri = document.BaseUri + OpenApiConstants.ComponentsSegment;
string location;

// Register Schema
foreach (var item in document.Components.Schemas)
{
var location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key;
if (item.Value.GetId() != null)
{
location = document.BaseUri + item.Value.GetId().ToString();
}
else
{
location = version == OpenApiSpecVersion.OpenApi2_0
? document.BaseUri + "/" + OpenApiConstants.Definitions + "/" + item.Key
: baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key;
}
Comment on lines +22 to +31

Check notice

Code scanning / CodeQL

Missed ternary opportunity

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

workspace.RegisterComponent(location, item.Value);
}

// Register Parameters
foreach (var item in document.Components.Parameters)
{
var location = baseUri + ReferenceType.Parameter.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Parameter.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register Responses
foreach (var item in document.Components.Responses)
{
var location = baseUri + ReferenceType.Response.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Response.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register RequestBodies
foreach (var item in document.Components.RequestBodies)
{
var location = baseUri + ReferenceType.RequestBody.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.RequestBody.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register Links
foreach (var item in document.Components.Links)
{
var location = baseUri + ReferenceType.Link.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Link.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register Callbacks
foreach (var item in document.Components.Callbacks)
{
var location = baseUri + ReferenceType.Callback.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Callback.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register PathItems
foreach (var item in document.Components.PathItems)
{
var location = baseUri + ReferenceType.PathItem.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.PathItem.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register Examples
foreach (var item in document.Components.Examples)
{
var location = baseUri + ReferenceType.Example.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Example.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register Headers
foreach (var item in document.Components.Headers)
{
var location = baseUri + ReferenceType.Header.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.Header.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}

// Register SecuritySchemes
foreach (var item in document.Components.SecuritySchemes)
{
var location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key;
location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key;
workspace.RegisterComponent(location, item.Value);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\src\Microsoft.OpenApi.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="**\*.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<EmbeddedResource Include="**\*.yaml" Exclude="**\bin\**;**\obj\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="**\*.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<EmbeddedResource Include="**\*.json" Exclude="**\bin\**;**\obj\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
_openApiDoc_2.Workspace.RegisterComponents(_openApiDoc_2);
_openApiDoc.Workspace.RegisterComponents(_openApiDoc_2, OpenApiSpecVersion.OpenApi3_1);
_openApiDoc_2.Workspace.RegisterComponents(_openApiDoc_2, OpenApiSpecVersion.OpenApi3_1);

_localPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc_2)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ namespace Microsoft.OpenApi.Models
public const string Callbacks = "callbacks";
public const string ClientCredentials = "clientCredentials";
public const string Components = "components";
public const string ComponentsSegment = "/components/";
public const string Consumes = "consumes";
public const string Contact = "contact";
public const string Content = "content";
Expand Down