diff --git a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
index 34b546352..5dcf17f7a 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
@@ -630,6 +630,11 @@ public static class OpenApiConstants
///
public const string V2ReferenceUri = "https://registry/definitions/";
+ ///
+ /// The default registry uri for OpenApi documents and workspaces
+ ///
+ public const string BaseRegistryUri = "https://openapi.net/";
+
#region V2.0
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
index 42b6734f7..28ed47325 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
@@ -10,7 +10,7 @@
using System.Threading;
using System.Threading.Tasks;
using Json.Schema;
-using Microsoft.OpenApi.Exceptions;
+using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Services;
@@ -94,8 +94,12 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IBaseDo
///
/// Parameter-less constructor
///
- public OpenApiDocument() { }
-
+ public OpenApiDocument()
+ {
+ Workspace = new OpenApiWorkspace();
+ BaseUri = new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid().ToString());
+ }
+
///
/// Initializes a copy of an an object
///
@@ -441,30 +445,17 @@ private static void WriteHostInfoV2(IOpenApiWriter writer, IList
}
///
- /// Walk the OpenApiDocument and resolve unresolved references
+ /// Walks the OpenApiDocument and sets the host document for all IOpenApiReferenceable objects
+ /// and resolves JsonSchema references
///
- ///
- /// This method will be replaced by a LoadExternalReferences in the next major update to this library.
- /// Resolving references at load time is going to go away.
- ///
public IEnumerable ResolveReferences()
{
- var resolver = new OpenApiReferenceResolver(this, false);
+ var resolver = new ReferenceResolver(this);
var walker = new OpenApiWalker(resolver);
walker.Walk(this);
return resolver.Errors;
}
- ///
- /// Walks the OpenApiDocument and sets the host document for all referenceable objects
- ///
- public void SetHostDocument()
- {
- var resolver = new HostDocumentResolver(this);
- var walker = new OpenApiWalker(resolver);
- walker.Walk(this);
- }
-
///
/// Load the referenced object from a object
///
@@ -488,6 +479,33 @@ public IOpenApiReferenceable ResolveReference(OpenApiReference reference)
return ResolveReference(reference, false);
}
+ ///
+ /// Resolves JsonSchema refs
+ ///
+ ///
+ /// A JsonSchema ref.
+ public JsonSchema ResolveJsonSchemaReference(Uri referenceUri)
+ {
+ string uriLocation;
+ string id = referenceUri.OriginalString.Split('/')?.Last();
+ string relativePath = "/components/" + ReferenceType.Schema.GetDisplayName() + "/" + id;
+
+ if (referenceUri.OriginalString.StartsWith("#"))
+ {
+ // Local reference
+ uriLocation = BaseUri + relativePath;
+ }
+ else
+ {
+ // External reference
+ var externalUri = referenceUri.OriginalString.Split('#').First();
+ var externalDocId = Workspace.GetDocumentId(externalUri);
+ uriLocation = externalDocId + relativePath;
+ }
+
+ return (JsonSchema)Workspace.ResolveReference(uriLocation);
+ }
+
///
/// Takes in an OpenApi document instance and generates its hash value
///
@@ -532,16 +550,6 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool
return null;
}
- // Todo: Verify if we need to check to see if this external reference is actually targeted at this document.
- if (useExternal)
- {
- if (this.Workspace == null)
- {
- throw new ArgumentException(Properties.SRResource.WorkspaceRequredForExternalReferenceResolution);
- }
- return this.Workspace.ResolveReference(reference);
- }
-
if (!reference.Type.HasValue)
{
throw new ArgumentException(Properties.SRResource.LocalReferenceRequiresType);
@@ -562,51 +570,16 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool
return null;
}
- if (this.Components == null)
- {
- throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, reference.Id));
- }
-
- try
- {
- switch (reference.Type)
- {
- case ReferenceType.PathItem:
- return Components.PathItems[reference.Id];
- case ReferenceType.Response:
- return Components.Responses[reference.Id];
-
- case ReferenceType.Parameter:
- return Components.Parameters[reference.Id];
-
- case ReferenceType.Example:
- return Components.Examples[reference.Id];
-
- case ReferenceType.RequestBody:
- return Components.RequestBodies[reference.Id];
+ string uriLocation;
+ string relativePath = "/components/" + reference.Type.GetDisplayName() + "/" + reference.Id;
- case ReferenceType.Header:
- return Components.Headers[reference.Id];
+ uriLocation = useExternal
+ ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath
+ : BaseUri + relativePath;
- case ReferenceType.SecurityScheme:
- return Components.SecuritySchemes[reference.Id];
-
- case ReferenceType.Link:
- return Components.Links[reference.Id];
-
- case ReferenceType.Callback:
- return Components.Callbacks[reference.Id];
-
- default:
- throw new OpenApiException(Properties.SRResource.InvalidReferenceType);
- }
- }
- catch (KeyNotFoundException)
- {
- throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, reference.Id));
- }
+ return Workspace.ResolveReference(uriLocation);
}
-
+
///
/// Parses a local file path or Url into an Open API document.
///
@@ -707,12 +680,6 @@ public JsonSchema FindSubschema(Json.Pointer.JsonPointer pointer, EvaluationOpti
{
throw new NotImplementedException();
}
-
- internal JsonSchema ResolveJsonSchemaReference(Uri reference)
- {
- var referencePath = string.Concat("https://registry", reference.OriginalString.Split('#').Last());
- return (JsonSchema)SchemaRegistry.Global.Get(new Uri(referencePath));
- }
}
internal class FindSchemaReferences : OpenApiVisitorBase
diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs
index b32810a64..648004ab4 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs
@@ -68,7 +68,7 @@ public OpenApiExample(OpenApiExample example)
{
Summary = example?.Summary ?? Summary;
Description = example?.Description ?? Description;
- Value = JsonNodeCloneHelper.Clone(example?.Value);
+ Value = example?.Value ?? JsonNodeCloneHelper.Clone(example?.Value);
ExternalValue = example?.ExternalValue ?? ExternalValue;
Extensions = example?.Extensions != null ? new Dictionary(example.Extensions) : null;
Reference = example?.Reference != null ? new(example?.Reference) : null;
diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
index 25d55f002..9655bf587 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
@@ -114,8 +114,8 @@ public OpenApiHeader(OpenApiHeader header)
Style = header?.Style ?? Style;
Explode = header?.Explode ?? Explode;
AllowReserved = header?.AllowReserved ?? AllowReserved;
- _schema = JsonNodeCloneHelper.CloneJsonSchema(header?.Schema);
- Example = JsonNodeCloneHelper.Clone(header?.Example);
+ Schema = header?.Schema != null ? JsonNodeCloneHelper.CloneJsonSchema(header?.Schema) : null;
+ Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header?.Example) : null;
Examples = header?.Examples != null ? new Dictionary(header.Examples) : null;
Content = header?.Content != null ? new Dictionary(header.Content) : null;
Extensions = header?.Extensions != null ? new Dictionary(header.Extensions) : null;
diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
index 048e29cb5..29003da51 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
@@ -168,9 +168,9 @@ public OpenApiParameter(OpenApiParameter parameter)
Style = parameter?.Style ?? Style;
Explode = parameter?.Explode ?? Explode;
AllowReserved = parameter?.AllowReserved ?? AllowReserved;
- _schema = JsonNodeCloneHelper.CloneJsonSchema(parameter?.Schema);
+ Schema = parameter?.Schema != null ? JsonNodeCloneHelper.CloneJsonSchema(parameter?.Schema) : null;
Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null;
- Example = JsonNodeCloneHelper.Clone(parameter?.Example);
+ Example = parameter?.Example != null ? JsonNodeCloneHelper.Clone(parameter?.Example) : null;
Content = parameter?.Content != null ? new Dictionary(parameter.Content) : null;
Extensions = parameter?.Extensions != null ? new Dictionary(parameter.Extensions) : null;
AllowEmptyValue = parameter?.AllowEmptyValue ?? AllowEmptyValue;
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs
index 0a28deab4..834e6aa3b 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs
@@ -33,7 +33,7 @@ private OpenApiCallback Target
/// The host OpenAPI document.
/// Optional: External resource in the reference.
/// It may be:
- /// 1. a absolute/relative file path, for example: ../commons/pet.json
+ /// 1. an absolute/relative file path, for example: ../commons/pet.json
/// 2. a Url, for example: http://localhost/pet.json
///
public OpenApiCallbackReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null)
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs
index bf1de88e1..b177bc059 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs
@@ -24,7 +24,10 @@ private OpenApiExample Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiExample resolved = new OpenApiExample(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ if (!string.IsNullOrEmpty(_summary)) resolved.Summary = _summary;
+ return resolved;
}
}
@@ -71,12 +74,12 @@ internal OpenApiExampleReference(OpenApiExample target, string referenceId)
public override string Description
{
get => string.IsNullOrEmpty(_description) ? Target.Description : _description;
- set => _description = value;
+ set => _description = value;
}
///
public override string Summary
- {
+ {
get => string.IsNullOrEmpty(_summary) ? Target.Summary : _summary;
set => _summary = value;
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs
index e934e3269..b878898bf 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs
@@ -24,7 +24,9 @@ private OpenApiHeader Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiHeader resolved = new OpenApiHeader(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
@@ -153,7 +155,7 @@ public override void SerializeAsV2(IOpenApiWriter writer)
private void SerializeInternal(IOpenApiWriter writer,
Action action)
{
- Utils.CheckArgumentNull(writer);;
+ Utils.CheckArgumentNull(writer);
action(writer, Target);
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs
index 15c48c96e..ffc7f3532 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs
@@ -22,7 +22,9 @@ private OpenApiLink Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiLink resolved = new OpenApiLink(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs
index 73f126b9e..6722bf1bd 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs
@@ -26,7 +26,9 @@ private OpenApiParameter Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiParameter resolved = new OpenApiParameter(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs
index ffd241118..21979093c 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs
@@ -23,7 +23,10 @@ private OpenApiPathItem Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiPathItem resolved = new OpenApiPathItem(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ if (!string.IsNullOrEmpty(_summary)) resolved.Summary = _summary;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs
index 4dec5c246..be6399c9f 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs
@@ -22,7 +22,9 @@ private OpenApiRequestBody Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiRequestBody resolved = new OpenApiRequestBody(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs
index 538b7d05d..cf5d06bb5 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs
@@ -22,7 +22,9 @@ private OpenApiResponse Target
get
{
_target ??= Reference.HostDocument?.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiResponse resolved = new OpenApiResponse(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
index 21473f9ff..74a6828d7 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
@@ -22,7 +22,9 @@ private OpenApiSecurityScheme Target
get
{
_target ??= Reference.HostDocument.ResolveReferenceTo(_reference);
- return _target;
+ OpenApiSecurityScheme resolved = new OpenApiSecurityScheme(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs
index 0d9017de6..7f0bd2a50 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs
@@ -22,7 +22,9 @@ private OpenApiTag Target
{
_target ??= Reference.HostDocument?.ResolveReferenceTo(_reference);
_target ??= new OpenApiTag() { Name = _reference.Id };
- return _target;
+ OpenApiTag resolved = new OpenApiTag(_target);
+ if (!string.IsNullOrEmpty(_description)) resolved.Description = _description;
+ return resolved;
}
}
diff --git a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs
index bbf928441..07fd6bfff 100644
--- a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs
+++ b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs
@@ -14,6 +14,8 @@
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Reader.Services;
+using System.Collections.Generic;
+using System;
namespace Microsoft.OpenApi.Reader
{
@@ -93,7 +95,7 @@ public async Task ReadAsync(JsonNode jsonNode,
}
}
- SetHostDocument(document);
+ ResolveReferences(diagnostic, document);
}
catch (OpenApiException ex)
{
@@ -198,9 +200,15 @@ private async Task LoadExternalRefs(OpenApiDocument document,
return await workspaceLoader.LoadAsync(new OpenApiReference() { ExternalResource = "/" }, document, format ?? OpenApiConstants.Json, null, cancellationToken);
}
- private void SetHostDocument(OpenApiDocument document)
+ private void ResolveReferences(OpenApiDiagnostic diagnostic, OpenApiDocument document)
{
- document.SetHostDocument();
+ List errors = new();
+ errors.AddRange(document.ResolveReferences());
+
+ foreach (var item in errors)
+ {
+ diagnostic.Errors.Add(item);
+ }
}
}
}
diff --git a/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs b/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs
index 135e69eee..4d44b98a9 100644
--- a/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs
+++ b/src/Microsoft.OpenApi/Reader/Services/OpenApiRemoteReferenceCollector.cs
@@ -1,6 +1,7 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
@@ -16,7 +17,7 @@ internal class OpenApiRemoteReferenceCollector : OpenApiVisitorBase
private readonly Dictionary _references = new();
///
- /// List of external references collected from OpenApiDocument
+ /// List of all external references collected from OpenApiDocument
///
public IEnumerable References
{
@@ -32,13 +33,13 @@ public IEnumerable References
///
public override void Visit(IOpenApiReferenceable referenceable)
{
- AddReference(referenceable.Reference);
+ AddExternalReferences(referenceable.Reference);
}
///
- /// Collect external reference
+ /// Collect external references
///
- private void AddReference(OpenApiReference reference)
+ private void AddExternalReferences(OpenApiReference reference)
{
if (reference is {IsExternal: true} &&
!_references.ContainsKey(reference.ExternalResource))
diff --git a/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs b/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs
index d80ffd714..abed56b2c 100644
--- a/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs
+++ b/src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs
@@ -26,7 +26,8 @@ internal async Task LoadAsync(OpenApiReference reference,
OpenApiDiagnostic diagnostic = null,
CancellationToken cancellationToken = default)
{
- _workspace.AddDocument(reference.ExternalResource, document);
+ _workspace.AddDocumentId(reference.ExternalResource, document.BaseUri);
+ _workspace.RegisterComponents(document);
document.Workspace = _workspace;
// Collect remote references by walking document
@@ -39,6 +40,7 @@ internal async Task LoadAsync(OpenApiReference reference,
// Walk references
foreach (var item in referenceCollector.References)
{
+
// If not already in workspace, load it and process references
if (!_workspace.Contains(item.ExternalResource))
{
@@ -51,7 +53,7 @@ internal async Task LoadAsync(OpenApiReference reference,
}
if (result.OpenApiDocument != null)
{
- var loadDiagnostic = await LoadAsync(item, result.OpenApiDocument, format, diagnostic, cancellationToken);
+ var loadDiagnostic = await LoadAsync(item, result.OpenApiDocument, format, diagnostic, cancellationToken);
diagnostic = loadDiagnostic;
}
}
diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
index 477f05f0d..0f814616f 100644
--- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
@@ -224,36 +224,38 @@ private static string BuildUrl(string scheme, string host, string basePath)
public static OpenApiDocument LoadOpenApi(RootNode rootNode)
{
- var openApidoc = new OpenApiDocument();
+ var openApiDoc = new OpenApiDocument();
var openApiNode = rootNode.GetMap();
- ParseMap(openApiNode, openApidoc, _openApiFixedFields, _openApiPatternFields);
+ ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields);
- if (openApidoc.Paths != null)
+ if (openApiDoc.Paths != null)
{
ProcessResponsesMediaTypes(
rootNode.GetMap(),
- openApidoc.Paths.Values
+ openApiDoc.Paths.Values
.SelectMany(path => path.Operations?.Values ?? Enumerable.Empty())
.SelectMany(operation => operation.Responses?.Values ?? Enumerable.Empty()),
openApiNode.Context);
}
- ProcessResponsesMediaTypes(rootNode.GetMap(), openApidoc.Components?.Responses?.Values, openApiNode.Context);
+ ProcessResponsesMediaTypes(rootNode.GetMap(), openApiDoc.Components?.Responses?.Values, openApiNode.Context);
// Post Process OpenApi Object
- if (openApidoc.Servers == null)
+ if (openApiDoc.Servers == null)
{
- openApidoc.Servers = new List();
+ openApiDoc.Servers = new List();
}
- MakeServers(openApidoc.Servers, openApiNode.Context, rootNode);
+ MakeServers(openApiDoc.Servers, openApiNode.Context, rootNode);
- FixRequestBodyReferences(openApidoc);
- RegisterComponentsSchemasInGlobalRegistry(openApidoc.Components?.Schemas);
+ FixRequestBodyReferences(openApiDoc);
- return openApidoc;
+ // Register components
+ openApiDoc.Workspace.RegisterComponents(openApiDoc);
+
+ return openApiDoc;
}
private static void ProcessResponsesMediaTypes(MapNode mapNode, IEnumerable responses, ParsingContext context)
diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs
index 1474c81a1..a6ca78101 100644
--- a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs
@@ -43,13 +43,6 @@ public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument h
var components = new OpenApiComponents();
ParseMap(mapNode, components, _componentsFixedFields, _componentsPatternFields);
-
- foreach (var schema in components.Schemas)
- {
- var refUri = new Uri(OpenApiConstants.V3ReferenceUri + schema.Key);
- SchemaRegistry.Global.Register(refUri, schema.Value);
- }
-
return components;
}
}
diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs
index 55174f34e..3ed838de9 100644
--- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs
@@ -4,6 +4,7 @@
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Reader.ParseNodes;
+using Microsoft.OpenApi.Services;
namespace Microsoft.OpenApi.Reader.V3
{
@@ -47,11 +48,14 @@ internal static partial class OpenApiV3Deserializer
public static OpenApiDocument LoadOpenApi(RootNode rootNode)
{
- var openApiNode = rootNode.GetMap();
var openApiDoc = new OpenApiDocument();
+ var openApiNode = rootNode.GetMap();
ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields);
+ // Register components
+ openApiDoc.Workspace.RegisterComponents(openApiDoc);
+
return openApiDoc;
}
}
diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs
index a1a399bd2..278c2043e 100644
--- a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs
@@ -42,12 +42,6 @@ public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument h
ParseMap(mapNode, components, _componentsFixedFields, _componentsPatternFields);
- foreach (var schema in components.Schemas)
- {
- var refUri = new Uri(OpenApiConstants.V3ReferenceUri + schema.Key);
- SchemaRegistry.Global.Register(refUri, schema.Value);
- }
-
return components;
}
}
diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs
index c868ab497..e4de78613 100644
--- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs
@@ -1,6 +1,8 @@
-using Microsoft.OpenApi.Extensions;
+using System;
+using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Reader.ParseNodes;
+using Microsoft.OpenApi.Services;
namespace Microsoft.OpenApi.Reader.V31
{
@@ -9,7 +11,7 @@ namespace Microsoft.OpenApi.Reader.V31
/// runtime Open API object model.
///
internal static partial class OpenApiV31Deserializer
- {
+ {
private static readonly FixedFieldMap _openApiFixedFields = new()
{
{
@@ -45,11 +47,14 @@ internal static partial class OpenApiV31Deserializer
public static OpenApiDocument LoadOpenApi(RootNode rootNode)
{
- var openApiNode = rootNode.GetMap();
var openApiDoc = new OpenApiDocument();
+ var openApiNode = rootNode.GetMap();
ParseMap(openApiNode, openApiDoc, _openApiFixedFields, _openApiPatternFields);
+ // Register components
+ openApiDoc.Workspace.RegisterComponents(openApiDoc);
+
return openApiDoc;
}
}
diff --git a/src/Microsoft.OpenApi/Services/HostDocumentResolver.cs b/src/Microsoft.OpenApi/Services/HostDocumentResolver.cs
deleted file mode 100644
index c11d8fed3..000000000
--- a/src/Microsoft.OpenApi/Services/HostDocumentResolver.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-
-namespace Microsoft.OpenApi.Services
-{
- internal class HostDocumentResolver : OpenApiVisitorBase
- {
- private readonly OpenApiDocument _currentDocument;
-
- public HostDocumentResolver(OpenApiDocument currentDocument)
- {
- _currentDocument = currentDocument;
- }
-
- ///
- /// Visits the referenceable element in the host document
- ///
- /// The referenceable element in the doc.
- public override void Visit(IOpenApiReferenceable referenceable)
- {
- if (referenceable.Reference != null)
- {
- referenceable.Reference.HostDocument = _currentDocument;
- }
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs
new file mode 100644
index 000000000..9f129c016
--- /dev/null
+++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs
@@ -0,0 +1,88 @@
+// 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)
+ {
+ if (document?.Components == null) return;
+
+ var baseUri = document.BaseUri + "/components/";
+
+ // Register Schema
+ foreach (var item in document.Components.Schemas)
+ {
+ var location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key;
+ workspace.RegisterComponent(location, item.Value);
+ }
+
+ // Register Parameters
+ foreach (var item in document.Components.Parameters)
+ {
+ var 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;
+ workspace.RegisterComponent(location, item.Value);
+ }
+
+ // Register RequestBodies
+ foreach (var item in document.Components.RequestBodies)
+ {
+ var 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;
+ workspace.RegisterComponent(location, item.Value);
+ }
+
+ // Register Callbacks
+ foreach (var item in document.Components.Callbacks)
+ {
+ var 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;
+ workspace.RegisterComponent(location, item.Value);
+ }
+
+ // Register Examples
+ foreach (var item in document.Components.Examples)
+ {
+ var 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;
+ workspace.RegisterComponent(location, item.Value);
+ }
+
+ // Register SecuritySchemes
+ foreach (var item in document.Components.SecuritySchemes)
+ {
+ var location = baseUri + ReferenceType.SecurityScheme.GetDisplayName() + "/" + item.Key;
+ workspace.RegisterComponent(location, item.Value);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs b/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs
deleted file mode 100644
index 43f1b7877..000000000
--- a/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Json.Schema;
-using Microsoft.OpenApi.Exceptions;
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-
-namespace Microsoft.OpenApi.Services
-{
- ///
- /// This class is used to walk an OpenApiDocument and convert unresolved references to references to populated objects
- ///
- public class OpenApiReferenceResolver : OpenApiVisitorBase
- {
- private OpenApiDocument _currentDocument;
- private readonly bool _resolveRemoteReferences;
- private List _errors = new();
-
- ///
- /// Initializes the class.
- ///
- public OpenApiReferenceResolver(OpenApiDocument currentDocument, bool resolveRemoteReferences = true)
- {
- _currentDocument = currentDocument;
- _resolveRemoteReferences = resolveRemoteReferences;
- }
-
- ///
- /// List of errors related to the OpenApiDocument
- ///
- public IEnumerable Errors => _errors;
-
- ///
- /// Resolves tags in OpenApiDocument
- ///
- ///
- public override void Visit(OpenApiDocument doc)
- {
- if (doc.Tags != null)
- {
- ResolveTags(doc.Tags);
- }
- }
-
- ///
- /// Visits the referenceable element in the host document
- ///
- /// The referenceable element in the doc.
- public override void Visit(IOpenApiReferenceable referenceable)
- {
- if (referenceable.Reference != null)
- {
- referenceable.Reference.HostDocument = _currentDocument;
- }
- }
-
- ///
- /// Resolves references in components
- ///
- ///
- public override void Visit(OpenApiComponents components)
- {
- ResolveMap(components.Parameters);
- ResolveMap(components.RequestBodies);
- ResolveMap(components.Responses);
- ResolveMap(components.Links);
- ResolveMap(components.Callbacks);
- ResolveMap(components.Examples);
- components.Schemas = ResolveJsonSchemas(components.Schemas);
- ResolveMap(components.PathItems);
- ResolveMap(components.SecuritySchemes);
- ResolveMap(components.Headers);
- }
-
- ///
- /// Resolves all references used in callbacks
- ///
- ///
- public override void Visit(IDictionary callbacks)
- {
- ResolveMap(callbacks);
- }
-
- ///
- /// Resolves all references used in webhooks
- ///
- ///
- public override void Visit(IDictionary webhooks)
- {
- ResolveMap(webhooks);
- }
-
- ///
- /// Resolve all references used in an operation
- ///
- public override void Visit(OpenApiOperation operation)
- {
- ResolveObject(operation.RequestBody, r => operation.RequestBody = r);
- ResolveList(operation.Parameters);
-
- if (operation.Tags != null)
- {
- ResolveTags(operation.Tags);
- }
- }
-
- ///
- /// Resolve all references used in mediaType object
- ///
- ///
- public override void Visit(OpenApiMediaType mediaType)
- {
- ResolveJsonSchema(mediaType.Schema, r => mediaType.Schema = r ?? mediaType.Schema);
- }
-
- ///
- /// Resolve all references to examples
- ///
- ///
- public override void Visit(IDictionary examples)
- {
- ResolveMap(examples);
- }
-
- ///
- /// Resolve all references to responses
- ///
- 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
- ///
- public override void Visit(OpenApiSecurityRequirement securityRequirement)
- {
- foreach (var scheme in securityRequirement.Keys.ToList())
- {
- ResolveObject(scheme, (resolvedScheme) =>
- {
- if (resolvedScheme != null)
- {
- // If scheme was unresolved
- // copy Scopes and remove old unresolved scheme
- var scopes = securityRequirement[scheme];
- securityRequirement.Remove(scheme);
- securityRequirement.Add(resolvedScheme, scopes);
- }
- });
- }
- }
-
- ///
- /// Resolve all references to parameters
- ///
- public override void Visit(IList parameters)
- {
- ResolveList(parameters);
- }
-
- ///
- /// Resolve all references used in a parameter
- ///
- public override void Visit(OpenApiParameter parameter)
- {
- ResolveJsonSchema(parameter.Schema, r => parameter.Schema = r);
- ResolveMap(parameter.Examples);
- }
-
- ///
- /// Resolve all references to links
- ///
- public override void Visit(IDictionary links)
- {
- ResolveMap(links);
- }
-
- ///
- /// Resolve all references used in a schem
- ///
- ///
- public override void Visit(ref JsonSchema schema)
- {
- var reference = schema.GetRef();
- var description = schema.GetDescription();
- var summary = schema.GetSummary();
-
- if (schema.Keywords.Count.Equals(1) && reference != null)
- {
- schema = ResolveJsonSchemaReference(reference, description, summary);
- }
-
- var builder = new JsonSchemaBuilder();
- if (schema?.Keywords is { } keywords)
- {
- foreach (var keyword in keywords)
- {
- builder.Add(keyword);
- }
- }
-
- ResolveJsonSchema(schema.GetItems(), r => builder.Items(r));
- ResolveJsonSchemaList((IList)schema.GetOneOf(), r => builder.OneOf(r));
- ResolveJsonSchemaList((IList)schema.GetAllOf(), r => builder.AllOf(r));
- ResolveJsonSchemaList((IList)schema.GetAnyOf(), r => builder.AnyOf(r));
- ResolveJsonSchemaMap((IDictionary)schema.GetProperties(), r => builder.Properties((IReadOnlyDictionary)r));
- ResolveJsonSchema(schema.GetAdditionalProperties(), r => builder.AdditionalProperties(r));
-
- schema = builder.Build();
- }
-
- ///
- /// Visits an IBaseDocument instance
- ///
- ///
- public override void Visit(IBaseDocument document) { }
-
- private Dictionary ResolveJsonSchemas(IDictionary schemas)
- {
- var resolvedSchemas = new Dictionary();
- foreach (var schema in schemas)
- {
- var schemaValue = schema.Value;
- Visit(ref schemaValue);
- resolvedSchemas[schema.Key] = schemaValue;
- }
-
- return resolvedSchemas;
- }
-
- ///
- /// Resolves the target to a JSON schema reference by retrieval from Schema registry
- ///
- /// The JSON schema reference.
- /// The schema's description.
- /// The schema's summary.
- ///
- public JsonSchema ResolveJsonSchemaReference(Uri reference, string description = null, string summary = null)
- {
- var refUri = $"https://registry{reference.OriginalString.Split('#').LastOrDefault()}";
- var resolvedSchema = (JsonSchema)SchemaRegistry.Global.Get(new Uri(refUri));
-
- if (resolvedSchema != null)
- {
- var resolvedSchemaBuilder = new JsonSchemaBuilder();
-
- foreach (var keyword in resolvedSchema.Keywords)
- {
- resolvedSchemaBuilder.Add(keyword);
-
- // Replace the resolved schema's description with that of the schema reference
- if (!string.IsNullOrEmpty(description))
- {
- resolvedSchemaBuilder.Description(description);
- }
-
- // Replace the resolved schema's summary with that of the schema reference
- if (!string.IsNullOrEmpty(summary))
- {
- resolvedSchemaBuilder.Summary(summary);
- }
- }
-
- return resolvedSchemaBuilder.Build();
- }
- else
- {
- var referenceId = reference.OriginalString.Split('/').LastOrDefault();
- throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, referenceId));
- }
- }
-
- ///
- /// Replace references to tags with either tag objects declared in components, or inline tag object
- ///
- private void ResolveTags(IList tags)
- {
- for (var i = 0; i < tags.Count; i++)
- {
- var tag = tags[i];
- if (IsUnresolvedReference(tag))
- {
- var resolvedTag = ResolveReference(tag.Reference);
-
- if (resolvedTag == null)
- {
- resolvedTag = new()
- {
- Name = tag.Reference.Id
- };
- }
- tags[i] = resolvedTag;
- }
- }
- }
-
- private void ResolveObject(T entity, Action assign) where T : class, IOpenApiReferenceable, new()
- {
- if (entity == null) return;
-
- if (IsUnresolvedReference(entity))
- {
- assign(ResolveReference(entity.Reference));
- }
- }
-
- private void ResolveJsonSchema(JsonSchema schema, Action assign)
- {
- if (schema == null) return;
- var reference = schema.GetRef();
- var description = schema.GetDescription();
- var summary = schema.GetSummary();
-
- if (reference != null)
- {
- assign(ResolveJsonSchemaReference(reference, description, summary));
- }
- }
-
- private void ResolveList(IList list) where T : class, IOpenApiReferenceable, new()
- {
- if (list == null) return;
-
- for (var i = 0; i < list.Count; i++)
- {
- var entity = list[i];
- if (IsUnresolvedReference(entity))
- {
- list[i] = ResolveReference(entity.Reference);
- }
- }
- }
-
- private void ResolveJsonSchemaList(IList list, Action> assign)
- {
- if (list == null) return;
-
- for (int i = 0; i < list.Count; i++)
- {
- var entity = list[i];
- var reference = entity?.GetRef();
- if (reference != null)
- {
- list[i] = ResolveJsonSchemaReference(reference);
- }
- }
-
- assign(list.ToList());
- }
-
- private void ResolveMap(IDictionary map) where T : class, IOpenApiReferenceable, new()
- {
- if (map == null) return;
-
- foreach (var key in map.Keys.ToList())
- {
- var entity = map[key];
- if (IsUnresolvedReference(entity))
- {
- map[key] = ResolveReference(entity.Reference);
- }
- }
- }
-
- private void ResolveJsonSchemaMap(IDictionary map, Action> assign)
- {
- if (map == null) return;
-
- foreach (var key in map.Keys.ToList())
- {
- var entity = map[key];
- var reference = entity.GetRef();
- if (reference != null)
- {
- map[key] = ResolveJsonSchemaReference(reference);
- }
- }
-
- assign(map.ToDictionary(e => e.Key, e => e.Value));
- }
-
- private T ResolveReference(OpenApiReference reference) where T : class, IOpenApiReferenceable, new()
- {
- if (string.IsNullOrEmpty(reference?.ExternalResource))
- {
- try
- {
- return _currentDocument.ResolveReference(reference, false) as T;
- }
- catch (OpenApiException ex)
- {
- _errors.Add(new OpenApiReferenceError(ex));
- return null;
- }
- }
- // The concept of merging references with their target at load time is going away in the next major version
- // External references will not support this approach.
- //else if (_resolveRemoteReferences == true)
- //{
- // if (_currentDocument.Workspace == null)
- // {
- // _errors.Add(new OpenApiReferenceError(reference,"Cannot resolve external references for documents not in workspaces."));
- // // Leave as unresolved reference
- // return new T()
- // {
- // UnresolvedReference = true,
- // Reference = reference
- // };
- // }
- // var target = _currentDocument.Workspace.ResolveReference(reference);
-
- // // TODO: If it is a document fragment, then we should resolve it within the current context
-
- // return target as T;
- //}
- else
- {
- // Leave as unresolved reference
- return new()
- {
- UnresolvedReference = true,
- Reference = reference
- };
- }
- }
-
- private bool IsUnresolvedReference(IOpenApiReferenceable possibleReference)
- {
- return possibleReference != null && possibleReference.UnresolvedReference;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs
index 63c1defaf..ca3fb32d0 100644
--- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs
+++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs
@@ -4,9 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using Json.Schema;
-using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
@@ -17,37 +15,16 @@ namespace Microsoft.OpenApi.Services
///
public class OpenApiWorkspace
{
- private readonly Dictionary _documents = new();
- private readonly Dictionary _fragments = new();
- private readonly Dictionary _schemaFragments = new();
- private readonly Dictionary _artifacts = new();
-
- ///
- /// A list of OpenApiDocuments contained in the workspace
- ///
- public IEnumerable Documents
- {
- get
- {
- return _documents.Values;
- }
- }
-
- ///
- /// A list of document fragments that are contained in the workspace
- ///
- public IEnumerable Fragments { get; }
+ private readonly Dictionary _documentsIdRegistry = new();
+ private readonly Dictionary _artifactsRegistry = new();
+ private readonly Dictionary _jsonSchemaRegistry = new();
+ private readonly Dictionary _IOpenApiReferenceableRegistry = new();
///
/// The base location from where all relative references are resolved
///
public Uri BaseUrl { get; }
-
- ///
- /// A list of document fragments that are contained in the workspace
- ///
- public IEnumerable Artifacts { get; }
-
+
///
/// Initialize workspace pointing to a base URL to allow resolving relative document locations. Use a file:// url to point to a folder
///
@@ -62,7 +39,7 @@ public OpenApiWorkspace(Uri baseUrl)
///
public OpenApiWorkspace()
{
- BaseUrl = new("file://" + Environment.CurrentDirectory + $"{Path.DirectorySeparatorChar}" );
+ BaseUrl = new Uri(OpenApiConstants.BaseRegistryUri);
}
///
@@ -71,133 +48,119 @@ public OpenApiWorkspace()
public OpenApiWorkspace(OpenApiWorkspace workspace) { }
///
- /// Verify if workspace contains a document based on its URL.
+ /// Returns the total count of all the components in the workspace registry
///
- /// A relative or absolute URL of the file. Use file:// for folder locations.
- /// Returns true if a matching document is found.
- public bool Contains(string location)
+ ///
+ public int ComponentsCount()
{
- var key = ToLocationUrl(location);
- return _documents.ContainsKey(key) || _fragments.ContainsKey(key) || _artifacts.ContainsKey(key);
+ return _IOpenApiReferenceableRegistry.Count + _jsonSchemaRegistry.Count + _artifactsRegistry.Count;
}
///
- /// Add an OpenApiDocument to the workspace.
+ /// Registers a component in the component registry.
///
///
- ///
- public void AddDocument(string location, OpenApiDocument document)
+ ///
+ /// true if the component is successfully registered; otherwise false.
+ public bool RegisterComponent(string location, T component)
{
- document.Workspace = this;
- _documents.Add(ToLocationUrl(location), document);
+ var uri = ToLocationUrl(location);
+ if (component is IBaseDocument schema)
+ {
+ if (!_jsonSchemaRegistry.ContainsKey(uri))
+ {
+ _jsonSchemaRegistry[uri] = schema;
+ return true;
+ }
+ }
+ else if (component is IOpenApiReferenceable referenceable)
+ {
+ if (!_IOpenApiReferenceableRegistry.ContainsKey(uri))
+ {
+ _IOpenApiReferenceableRegistry[uri] = referenceable;
+ return true;
+ }
+ }
+ else if (component is Stream stream)
+ {
+ if (!_artifactsRegistry.ContainsKey(uri))
+ {
+ _artifactsRegistry[uri] = stream;
+ return true;
+ }
+ }
+
+ return false;
}
///
- /// Adds a fragment of an OpenApiDocument to the workspace.
+ /// Adds a document id to the dictionaries of document locations and their ids.
///
- ///
- ///
- /// Not sure how this is going to work. Does the reference just point to the fragment as a whole, or do we need to
- /// to be able to point into the fragment. Keeping it private until we figure it out.
- ///
- public void AddFragment(string location, IOpenApiReferenceable fragment)
+ ///
+ ///
+ public void AddDocumentId(string key, Uri value)
{
- _fragments.Add(ToLocationUrl(location), fragment);
+ if (!_documentsIdRegistry.ContainsKey(key))
+ {
+ _documentsIdRegistry[key] = value;
+ }
}
///
- /// Adds a schema fragment of an OpenApiDocument to the workspace.
+ /// Retrieves the document id given a key.
///
- ///
- ///
- public void AddSchemaFragment(string location, JsonSchema fragment)
+ ///
+ /// The document id of the given key.
+ public Uri GetDocumentId(string key)
{
- _schemaFragments.Add(ToLocationUrl(location), fragment);
+ if (_documentsIdRegistry.TryGetValue(key, out var id))
+ {
+ return id;
+ }
+ return null;
}
///
- /// Add a stream based artificat to the workspace. Useful for images, examples, alternative schemas.
+ /// Verify if workspace contains a component based on its URL.
///
- ///
- ///
- public void AddArtifact(string location, Stream artifact)
+ /// A relative or absolute URL of the file. Use file:// for folder locations.
+ /// Returns true if a matching document is found.
+ public bool Contains(string location)
{
- _artifacts.Add(ToLocationUrl(location), artifact);
+ var key = ToLocationUrl(location);
+ return _IOpenApiReferenceableRegistry.ContainsKey(key) || _jsonSchemaRegistry.ContainsKey(key) || _artifactsRegistry.ContainsKey(key);
}
///
- /// Returns the target of an OpenApiReference from within the workspace.
+ /// Resolves a reference given a key.
///
- /// An instance of an OpenApiReference
- ///
- public IOpenApiReferenceable ResolveReference(OpenApiReference reference)
+ ///
+ ///
+ /// The resolved reference.
+ public T ResolveReference(string location)
{
- if (_documents.TryGetValue(new(BaseUrl, reference.ExternalResource), out var doc))
+ if (string.IsNullOrEmpty(location)) return default;
+
+ var uri = ToLocationUrl(location);
+ if (_IOpenApiReferenceableRegistry.TryGetValue(uri, out var referenceableValue))
{
- return doc.ResolveReference(reference, false);
+ return (T)referenceableValue;
}
- else if (_fragments.TryGetValue(new(BaseUrl, reference.ExternalResource), out var fragment))
+ else if (_jsonSchemaRegistry.TryGetValue(uri, out var schemaValue))
{
- var jsonPointer = new JsonPointer($"/{reference.Id ?? string.Empty}");
- return fragment.ResolveReference(jsonPointer);
+ return (T)schemaValue;
}
- return null;
- }
-
- ///
- /// Resolve the target of a JSON schema reference from within the workspace
- ///
- /// An instance of a JSON schema reference.
- ///
- public JsonSchema ResolveJsonSchemaReference(Uri reference)
- {
- var docs = _documents.Values;
- if (docs.Any())
+ else if (_artifactsRegistry.TryGetValue(uri, out var artifact))
{
- var doc = docs.FirstOrDefault();
- if (doc != null)
- {
- foreach (var jsonSchema in doc.Components.Schemas)
- {
- var refUri = new Uri(OpenApiConstants.V3ReferenceUri + jsonSchema.Key);
- SchemaRegistry.Global.Register(refUri, jsonSchema.Value);
- }
-
- var resolver = new OpenApiReferenceResolver(doc);
- return resolver.ResolveJsonSchemaReference(reference);
- }
- return null;
+ return (T)(object)artifact;
}
- else
- {
- foreach (var jsonSchema in _schemaFragments)
- {
- SchemaRegistry.Global.Register(reference, jsonSchema.Value);
- }
- return FetchSchemaFromRegistry(reference);
- }
- }
-
- ///
- ///
- ///
- ///
- ///
- public Stream GetArtifact(string location)
- {
- return _artifacts[ToLocationUrl(location)];
+ return default;
}
private Uri ToLocationUrl(string location)
{
return new(BaseUrl, location);
}
-
- private static JsonSchema FetchSchemaFromRegistry(Uri reference)
- {
- var resolvedSchema = (JsonSchema)SchemaRegistry.Global.Get(reference);
- return resolvedSchema;
- }
}
}
diff --git a/src/Microsoft.OpenApi/Services/ReferenceResolver.cs b/src/Microsoft.OpenApi/Services/ReferenceResolver.cs
new file mode 100644
index 000000000..ae568c6f1
--- /dev/null
+++ b/src/Microsoft.OpenApi/Services/ReferenceResolver.cs
@@ -0,0 +1,213 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using Json.Schema;
+using Microsoft.OpenApi.Exceptions;
+using System.Linq;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Extensions;
+
+namespace Microsoft.OpenApi.Services
+{
+ ///
+ /// This class is used to wallk an OpenApiDocument and sets the host document of OpenApiReferences
+ /// and resolves JsonSchema references.
+ ///
+ internal class ReferenceResolver : OpenApiVisitorBase
+ {
+ private readonly OpenApiDocument _currentDocument;
+ private readonly List _errors = new();
+
+ public ReferenceResolver(OpenApiDocument currentDocument)
+ {
+ _currentDocument = currentDocument;
+ }
+
+ ///
+ /// List of errors related to the OpenApiDocument
+ ///
+ public IEnumerable Errors => _errors;
+
+ ///
+ /// Visits the referenceable element in the host document
+ ///
+ /// The referenceable element in the doc.
+ public override void Visit(IOpenApiReferenceable referenceable)
+ {
+ if (referenceable.Reference != null)
+ {
+ referenceable.Reference.HostDocument = _currentDocument;
+ }
+ }
+
+ ///
+ /// Resolves schemas in components
+ ///
+ ///
+ public override void Visit(OpenApiComponents components)
+ {
+ components.Schemas = ResolveJsonSchemas(components.Schemas);
+ }
+
+ ///
+ /// Resolve all JsonSchema references used in mediaType object
+ ///
+ ///
+ public override void Visit(OpenApiMediaType mediaType)
+ {
+ ResolveJsonSchema(mediaType.Schema, r => mediaType.Schema = r ?? mediaType.Schema);
+ }
+
+ ///
+ /// Resolve all JsonSchema references used in a parameter
+ ///
+ public override void Visit(OpenApiParameter parameter)
+ {
+ ResolveJsonSchema(parameter.Schema, r => parameter.Schema = r);
+ }
+
+ ///
+ /// Resolve all references used in a JsonSchema
+ ///
+ ///
+ public override void Visit(ref JsonSchema schema)
+ {
+ var reference = schema.GetRef();
+ var description = schema.GetDescription();
+ var summary = schema.GetSummary();
+
+ if (schema.Keywords.Count.Equals(1) && reference != null)
+ {
+ schema = ResolveJsonSchemaReference(reference, description, summary);
+ }
+
+ var builder = new JsonSchemaBuilder();
+ if (schema?.Keywords is { } keywords)
+ {
+ foreach (var keyword in keywords)
+ {
+ builder.Add(keyword);
+ }
+ }
+
+ ResolveJsonSchema(schema.GetItems(), r => builder.Items(r));
+ ResolveJsonSchemaList((IList)schema.GetOneOf(), r => builder.OneOf(r));
+ ResolveJsonSchemaList((IList)schema.GetAllOf(), r => builder.AllOf(r));
+ ResolveJsonSchemaList((IList)schema.GetAnyOf(), r => builder.AnyOf(r));
+ ResolveJsonSchemaMap((IDictionary)schema.GetProperties(), r => builder.Properties((IReadOnlyDictionary)r));
+ ResolveJsonSchema(schema.GetAdditionalProperties(), r => builder.AdditionalProperties(r));
+
+ schema = builder.Build();
+ }
+
+ ///
+ /// Visits an IBaseDocument instance
+ ///
+ ///
+ public override void Visit(IBaseDocument document) { }
+
+ private Dictionary ResolveJsonSchemas(IDictionary schemas)
+ {
+ var resolvedSchemas = new Dictionary();
+ foreach (var schema in schemas)
+ {
+ var schemaValue = schema.Value;
+ Visit(ref schemaValue);
+ resolvedSchemas[schema.Key] = schemaValue;
+ }
+
+ return resolvedSchemas;
+ }
+
+ ///
+ /// Resolves the target to a JsonSchema reference by retrieval from Schema registry
+ ///
+ /// The JSON schema reference.
+ /// The schema's description.
+ /// The schema's summary.
+ ///
+ public JsonSchema ResolveJsonSchemaReference(Uri reference, string description = null, string summary = null)
+ {
+ var resolvedSchema = _currentDocument.ResolveJsonSchemaReference(reference);
+
+ if (resolvedSchema != null)
+ {
+ var resolvedSchemaBuilder = new JsonSchemaBuilder();
+
+ foreach (var keyword in resolvedSchema.Keywords)
+ {
+ resolvedSchemaBuilder.Add(keyword);
+
+ // Replace the resolved schema's description with that of the schema reference
+ if (!string.IsNullOrEmpty(description))
+ {
+ resolvedSchemaBuilder.Description(description);
+ }
+
+ // Replace the resolved schema's summary with that of the schema reference
+ if (!string.IsNullOrEmpty(summary))
+ {
+ resolvedSchemaBuilder.Summary(summary);
+ }
+ }
+
+ return resolvedSchemaBuilder.Build();
+ }
+ else
+ {
+ var referenceId = reference.OriginalString.Split('/').LastOrDefault();
+ throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, referenceId));
+ }
+ }
+
+ private void ResolveJsonSchema(JsonSchema schema, Action assign)
+ {
+ if (schema == null) return;
+ var reference = schema.GetRef();
+ var description = schema.GetDescription();
+ var summary = schema.GetSummary();
+
+ if (reference != null)
+ {
+ assign(ResolveJsonSchemaReference(reference, description, summary));
+ }
+ }
+
+ private void ResolveJsonSchemaList(IList list, Action> assign)
+ {
+ if (list == null) return;
+
+ for (int i = 0; i < list.Count; i++)
+ {
+ var entity = list[i];
+ var reference = entity?.GetRef();
+ if (reference != null)
+ {
+ list[i] = ResolveJsonSchemaReference(reference);
+ }
+ }
+
+ assign(list.ToList());
+ }
+
+ private void ResolveJsonSchemaMap(IDictionary map, Action> assign)
+ {
+ if (map == null) return;
+
+ foreach (var key in map.Keys.ToList())
+ {
+ var entity = map[key];
+ var reference = entity.GetRef();
+ if (reference != null)
+ {
+ map[key] = ResolveJsonSchemaReference(reference);
+ }
+ }
+
+ assign(map.ToDictionary(e => e.Key, e => e.Value));
+ }
+ }
+}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs
index 2eb86e4e6..9ec7afb3a 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs
@@ -57,10 +57,10 @@ public async Task DiagnosticReportMergedForExternalReference()
Assert.NotNull(result);
Assert.NotNull(result.OpenApiDocument.Workspace);
- Assert.True(result.OpenApiDocument.Workspace.Contains("TodoReference.yaml"));
- result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List
+ result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List
{
new OpenApiError("", "[File: ./TodoReference.yaml] Paths is a REQUIRED field at #/"),
+ new(new OpenApiException("[File: ./TodoReference.yaml] Invalid Reference identifier 'object-not-existing'."))
});
}
}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs
index aa8013bc2..868d4c52f 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs
@@ -59,14 +59,13 @@ public async Task LoadDocumentWithExternalReferenceShouldLoadBothDocumentsIntoWo
{
LoadExternalRefs = true,
CustomExternalLoader = new ResourceLoader(),
- BaseUrl = new("fie://c:\\")
+ BaseUrl = new("file://c:\\"),
};
ReadResult result;
result = await OpenApiDocument.LoadAsync("V3Tests/Samples/OpenApiWorkspace/TodoMain.yaml", settings);
Assert.NotNull(result.OpenApiDocument.Workspace);
- Assert.True(result.OpenApiDocument.Workspace.Contains("TodoComponents.yaml"));
var referencedSchema = result.OpenApiDocument
.Paths["/todos"]
@@ -75,6 +74,10 @@ public async Task LoadDocumentWithExternalReferenceShouldLoadBothDocumentsIntoWo
.Content["application/json"]
.Schema;
+ var x = referencedSchema.GetProperties().TryGetValue("subject", out var schema);
+ Assert.Equal(SchemaValueType.Object, referencedSchema.GetJsonType());
+ Assert.Equal(SchemaValueType.String, schema.GetJsonType());
+
var referencedParameter = result.OpenApiDocument
.Paths["/todos"]
.Operations[OperationType.Get]
diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs
index 99359881c..7cbd961fc 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Generic;
@@ -100,6 +100,12 @@ public void LoadResponseAndSchemaReference()
{
Schema = new JsonSchemaBuilder()
.Ref("#/definitions/SampleObject2")
+ .Description("Sample description")
+ .Required("name")
+ .Properties(
+ ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String)))
+ .Build()
}
}
}, options => options.Excluding(x => x.Reference)
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/ComparisonTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/ComparisonTests.cs
index ee9e1f401..b3e30c672 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/ComparisonTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/ComparisonTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System.IO;
@@ -18,15 +18,16 @@ public class ComparisonTests
[InlineData("minimal")]
[InlineData("basic")]
//[InlineData("definitions")] //Currently broken due to V3 references not behaving the same as V2
- public void EquivalentV2AndV3DocumentsShouldProductEquivalentObjects(string fileName)
+ public void EquivalentV2AndV3DocumentsShouldProduceEquivalentObjects(string fileName)
{
- OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader());
+ OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
using var streamV2 = Resources.GetStream(Path.Combine(SampleFolderPath, $"{fileName}.v2.yaml"));
using var streamV3 = Resources.GetStream(Path.Combine(SampleFolderPath, $"{fileName}.v3.yaml"));
var result1 = OpenApiDocument.Load(Path.Combine(SampleFolderPath, $"{fileName}.v2.yaml"));
var result2 = OpenApiDocument.Load(Path.Combine(SampleFolderPath, $"{fileName}.v3.yaml"));
- result2.OpenApiDocument.Should().BeEquivalentTo(result1.OpenApiDocument);
+ result2.OpenApiDocument.Should().BeEquivalentTo(result1.OpenApiDocument,
+ options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
result1.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(result2.OpenApiDiagnostic.Errors);
}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs
index d864f597d..611f2c3d5 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs
@@ -2,12 +2,15 @@
// Licensed under the MIT license.
using System;
+using System.Globalization;
using System.IO;
using System.Linq;
using FluentAssertions;
using Json.Schema;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Reader;
+using Microsoft.OpenApi.Writers;
+using VerifyXunit;
using Xunit;
namespace Microsoft.OpenApi.Readers.Tests.V2Tests
@@ -39,12 +42,12 @@ public void ShouldParseProducesInAnyOrder()
var okMediaType = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(new JsonSchemaBuilder().Ref("#/definitions/Item"))
+ Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(okSchema)
};
var errorMediaType = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/definitions/Error")
+ Schema = errorSchema
};
result.OpenApiDocument.Should().BeEquivalentTo(new OpenApiDocument
@@ -148,7 +151,8 @@ public void ShouldParseProducesInAnyOrder()
["Error"] = errorSchema
}
}
- });
+ }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
+
}
[Fact]
@@ -165,6 +169,7 @@ public void ShouldAssignSchemaToAllResponses()
.Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Item identifier."))));
var errorSchema = new JsonSchemaBuilder()
+ .Ref("#/definitions/Error")
.Properties(("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")),
("message", new JsonSchemaBuilder().Type(SchemaValueType.String)),
("fields", new JsonSchemaBuilder().Type(SchemaValueType.String)));
@@ -176,7 +181,6 @@ public void ShouldAssignSchemaToAllResponses()
var json = response.Value.Content["application/json"];
Assert.NotNull(json);
-
Assert.Equal(json.Schema.Keywords.Count, targetSchema.Keywords.Count);
var xml = response.Value.Content["application/xml"];
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs
index d11a87d7b..087220fa7 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs
@@ -133,14 +133,14 @@ public void ParseDocumentWithWebhooksShouldSucceed()
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"))
+ .Items(petSchema)
},
["application/xml"] = new OpenApiMediaType
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"))
+ .Items(petSchema)
}
}
}
@@ -156,7 +156,7 @@ public void ParseDocumentWithWebhooksShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema")
+ Schema = newPetSchema
}
}
},
@@ -169,7 +169,7 @@ public void ParseDocumentWithWebhooksShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema")
+ Schema = petSchema
}
}
}
@@ -181,10 +181,9 @@ public void ParseDocumentWithWebhooksShouldSucceed()
Components = components
};
- // Assert
- var schema = actual.OpenApiDocument.Webhooks["pets"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema;
+ // Assert
actual.OpenApiDiagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 });
- actual.OpenApiDocument.Should().BeEquivalentTo(expected);
+ actual.OpenApiDocument.Should().BeEquivalentTo(expected, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
}
[Fact]
@@ -261,13 +260,13 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds()
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"))
+ .Items(petSchema)
},
["application/xml"] = new OpenApiMediaType
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"))
+ .Items(petSchema)
}
}
}
@@ -283,7 +282,7 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema")
+ Schema = newPetSchema
}
}
},
@@ -296,7 +295,7 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema")
+ Schema = petSchema
},
}
}
@@ -322,7 +321,10 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds()
};
// Assert
- actual.OpenApiDocument.Should().BeEquivalentTo(expected, options => options.Excluding(x => x.Webhooks["pets"].Reference));
+ actual.OpenApiDocument.Should().BeEquivalentTo(expected, options => options
+ .Excluding(x => x.Webhooks["pets"].Reference)
+ .Excluding(x => x.Workspace)
+ .Excluding(y => y.BaseUri));
actual.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 });
}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs
index 25871e25e..50cadb81c 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Generic;
@@ -220,7 +220,7 @@ public void ParseBasicSchemaWithReferenceShouldSucceed()
SpecificationVersion = OpenApiSpecVersion.OpenApi3_0,
Errors = new List()
{
- new OpenApiError("", "Paths is a REQUIRED field at #/")
+ new OpenApiError("", "Paths is a REQUIRED field at #/")
}
});
@@ -228,22 +228,27 @@ public void ParseBasicSchemaWithReferenceShouldSucceed()
{
Schemas =
{
- ["ErrorModel"] = new JsonSchemaBuilder()
- .Ref("#/components/schemas/ErrorModel")
- .Type(SchemaValueType.Object)
- .Required("message", "code")
- .Properties(
- ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)),
- ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Minimum(100).Maximum(600))),
- ["ExtendedErrorModel"] = new JsonSchemaBuilder()
- .Ref("#/components/schemas/ExtendedErrorModel")
- .AllOf(
- new JsonSchemaBuilder()
- .Ref("#/components/schemas/ErrorModel"),
- new JsonSchemaBuilder()
- .Type(SchemaValueType.Object)
- .Required("rootCause")
- .Properties(("rootCause", new JsonSchemaBuilder().Type(SchemaValueType.String))))
+ ["ErrorModel"] = new JsonSchemaBuilder()
+ .Ref("#/components/schemas/ErrorModel")
+ .Type(SchemaValueType.Object)
+ .Required("message", "code")
+ .Properties(
+ ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Minimum(100).Maximum(600))),
+ ["ExtendedErrorModel"] = new JsonSchemaBuilder()
+ .Ref("#/components/schemas/ExtendedErrorModel")
+ .AllOf(
+ new JsonSchemaBuilder()
+ .Ref("#/components/schemas/ErrorModel")
+ .Type(SchemaValueType.Object)
+ .Properties(
+ ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Minimum(100).Maximum(600)),
+ ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)))
+ .Required("message", "code"),
+ new JsonSchemaBuilder()
+ .Type(SchemaValueType.Object)
+ .Required("rootCause")
+ .Properties(("rootCause", new JsonSchemaBuilder().Type(SchemaValueType.String))))
}
};
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs
index b337a5166..21d7e2884 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs
@@ -96,11 +96,11 @@ public void ParseDocumentFromInlineStringShouldSucceed()
Version = "0.9.1"
},
Paths = new OpenApiPaths()
- });
+ }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
result.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic()
- {
+ {
SpecificationVersion = OpenApiSpecVersion.OpenApi3_0,
Errors = new List()
{
@@ -117,7 +117,7 @@ public void ParseBasicDocumentWithMultipleServersShouldSucceed()
result.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic()
- {
+ {
SpecificationVersion = OpenApiSpecVersion.OpenApi3_0,
Errors = new List()
{
@@ -147,7 +147,7 @@ public void ParseBasicDocumentWithMultipleServersShouldSucceed()
}
},
Paths = new OpenApiPaths()
- });
+ }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
}
[Fact]
public void ParseBrokenMinimalDocumentShouldYieldExpectedDiagnostic()
@@ -163,7 +163,7 @@ public void ParseBrokenMinimalDocumentShouldYieldExpectedDiagnostic()
Version = "0.9"
},
Paths = new OpenApiPaths()
- });
+ }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
result.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic
@@ -191,7 +191,7 @@ public void ParseMinimalDocumentShouldSucceed()
Version = "0.9.1"
},
Paths = new OpenApiPaths()
- });
+ }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
result.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic()
@@ -207,7 +207,8 @@ public void ParseMinimalDocumentShouldSucceed()
[Fact]
public void ParseStandardPetStoreDocumentShouldSucceed()
{
- var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "petStore.yaml"));
+ using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "petStore.yaml"));
+ var result = OpenApiDocument.Load(stream, OpenApiConstants.Yaml);
var components = new OpenApiComponents
{
@@ -238,6 +239,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
("message", new JsonSchemaBuilder().Type(SchemaValueType.String)))
}
};
+ var petSchema = components.Schemas["pet1"];
+
+ var newPetSchema = components.Schemas["newPet"];
+
+ var errorModelSchema = components.Schemas["errorModel"];
var expectedDoc = new OpenApiDocument
{
@@ -307,13 +313,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/pet1"))
+ Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema)
},
["application/xml"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/pet1"))
+ Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema)
}
}
},
@@ -324,7 +328,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -335,7 +339,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -353,7 +357,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet")
+ Schema = newPetSchema
}
}
},
@@ -366,7 +370,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
},
}
},
@@ -377,7 +381,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -388,7 +392,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -425,11 +429,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
},
["application/xml"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
}
}
},
@@ -440,7 +444,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -451,7 +455,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -485,7 +489,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -496,7 +500,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -508,16 +512,17 @@ public void ParseStandardPetStoreDocumentShouldSucceed()
Components = components
};
- result.OpenApiDocument.Should().BeEquivalentTo(expectedDoc);
+ result.OpenApiDocument.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri));
- result.OpenApiDiagnostic.Should().BeEquivalentTo(
- new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 });
+ result.OpenApiDiagnostic.Should().BeEquivalentTo(
+ new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 });
}
[Fact]
public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
- var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "petStoreWithTagAndSecurity.yaml"));
+ using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "petStoreWithTagAndSecurity.yaml"));
+ var actual = OpenApiDocument.Load(stream, OpenApiConstants.Yaml);
var components = new OpenApiComponents
{
@@ -563,6 +568,12 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
}
};
+ var petSchema = components.Schemas["pet1"];
+
+ var newPetSchema = components.Schemas["newPet"];
+
+ var errorModelSchema = components.Schemas["errorModel"];
+
var tag1 = new OpenApiTag
{
Name = "tagName1",
@@ -574,6 +585,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
}
};
+
var tag2 = new OpenApiTag
{
Name = "tagName2",
@@ -622,12 +634,12 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
}
},
Servers = new List
- {
- new OpenApiServer
{
- Url = "http://petstore.swagger.io/api"
- }
- },
+ new OpenApiServer
+ {
+ Url = "http://petstore.swagger.io/api"
+ }
+ },
Paths = new OpenApiPaths
{
["/pets"] = new OpenApiPathItem
@@ -637,35 +649,35 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
[OperationType.Get] = new OpenApiOperation
{
Tags = new List
- {
- tag1,
- tag2
- },
+ {
+ tag1,
+ tag2
+ },
Description = "Returns all pets from the system that the user has access to",
OperationId = "findPets",
Parameters = new List
- {
- new OpenApiParameter
{
- Name = "tags",
- In = ParameterLocation.Query,
- Description = "tags to filter by",
- Required = false,
- Schema = new JsonSchemaBuilder()
- .Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Type(SchemaValueType.String))
+ new OpenApiParameter
+ {
+ Name = "tags",
+ In = ParameterLocation.Query,
+ Description = "tags to filter by",
+ Required = false,
+ Schema = new JsonSchemaBuilder()
+ .Type(SchemaValueType.Array)
+ .Items(new JsonSchemaBuilder().Type(SchemaValueType.String))
+ },
+ new OpenApiParameter
+ {
+ Name = "limit",
+ In = ParameterLocation.Query,
+ Description = "maximum number of results to return",
+ Required = false,
+ Schema = new JsonSchemaBuilder()
+ .Type(SchemaValueType.Integer)
+ .Format("int32")
+ }
},
- new OpenApiParameter
- {
- Name = "limit",
- In = ParameterLocation.Query,
- Description = "maximum number of results to return",
- Required = false,
- Schema = new JsonSchemaBuilder()
- .Type(SchemaValueType.Integer)
- .Format("int32")
- }
- },
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse
@@ -677,13 +689,13 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/pet1"))
+ .Items(petSchema)
},
["application/xml"] = new OpenApiMediaType
{
Schema = new JsonSchemaBuilder()
.Type(SchemaValueType.Array)
- .Items(new JsonSchemaBuilder().Ref("#/components/schemas/pet1"))
+ .Items(petSchema)
}
}
},
@@ -694,7 +706,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -705,7 +717,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -714,10 +726,10 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
[OperationType.Post] = new OpenApiOperation
{
Tags = new List
- {
- tag1,
- tag2
- },
+ {
+ tag1,
+ tag2
+ },
Description = "Creates a new pet in the store. Duplicates are allowed",
OperationId = "addPet",
RequestBody = new OpenApiRequestBody
@@ -728,7 +740,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet")
+ Schema = newPetSchema
}
}
},
@@ -741,7 +753,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
},
}
},
@@ -752,7 +764,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -763,23 +775,23 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
},
Security = new List
- {
- new OpenApiSecurityRequirement
{
- [securityScheme1] = new List(),
- [securityScheme2] = new List
+ new OpenApiSecurityRequirement
{
- "scope1",
- "scope2"
+ [securityScheme1] = new List(),
+ [securityScheme2] = new List
+ {
+ "scope1",
+ "scope2"
+ }
}
}
- }
}
}
},
@@ -793,18 +805,18 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
"Returns a user based on a single ID, if the user does not have access to the pet",
OperationId = "findPetById",
Parameters = new List
- {
- new OpenApiParameter
{
- Name = "id",
- In = ParameterLocation.Path,
- Description = "ID of pet to fetch",
- Required = true,
- Schema = new JsonSchemaBuilder()
- .Type(SchemaValueType.Integer)
- .Format("int64")
- }
- },
+ new OpenApiParameter
+ {
+ Name = "id",
+ In = ParameterLocation.Path,
+ Description = "ID of pet to fetch",
+ Required = true,
+ Schema = new JsonSchemaBuilder()
+ .Type(SchemaValueType.Integer)
+ .Format("int64")
+ }
+ },
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse
@@ -814,11 +826,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["application/json"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
},
["application/xml"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1")
+ Schema = petSchema
}
}
},
@@ -829,7 +841,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -840,7 +852,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -851,18 +863,18 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
Description = "deletes a single pet based on the ID supplied",
OperationId = "deletePet",
Parameters = new List
- {
- new OpenApiParameter
{
- Name = "id",
- In = ParameterLocation.Path,
- Description = "ID of pet to delete",
- Required = true,
- Schema = new JsonSchemaBuilder()
- .Type(SchemaValueType.Integer)
- .Format("int64")
- }
- },
+ new OpenApiParameter
+ {
+ Name = "id",
+ In = ParameterLocation.Path,
+ Description = "ID of pet to delete",
+ Required = true,
+ Schema = new JsonSchemaBuilder()
+ .Type(SchemaValueType.Integer)
+ .Format("int64")
+ }
+ },
Responses = new OpenApiResponses
{
["204"] = new OpenApiResponse
@@ -876,7 +888,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
},
@@ -887,7 +899,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
{
["text/html"] = new OpenApiMediaType
{
- Schema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel")
+ Schema = errorModelSchema
}
}
}
@@ -898,26 +910,26 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
},
Components = components,
Tags = new List
- {
- new OpenApiTag
{
- Name = "tagName1",
- Description = "tagDescription1"
- }
- },
+ new OpenApiTag
+ {
+ Name = "tagName1",
+ Description = "tagDescription1"
+ }
+ },
SecurityRequirements = new List
- {
- new OpenApiSecurityRequirement
{
- [securityScheme1] = new List(),
- [securityScheme2] = new List
+ new OpenApiSecurityRequirement
{
- "scope1",
- "scope2",
- "scope3"
+ [securityScheme1] = new List(),
+ [securityScheme2] = new List
+ {
+ "scope1",
+ "scope2",
+ "scope3"
+ }
}
}
- }
};
actual.OpenApiDocument.Should().BeEquivalentTo(expected, options => options
@@ -927,12 +939,14 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
.Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference.HostDocument)
.Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[0].Reference.HostDocument)
.Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[1].Reference.HostDocument)
- .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[1].Reference.HostDocument));
-
+ .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[1].Reference.HostDocument)
+ .Excluding(x => x.Workspace)
+ .Excluding(y => y.BaseUri));
actual.OpenApiDiagnostic.Should().BeEquivalentTo(
new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 });
}
+
[Fact]
public void ParsePetStoreExpandedShouldSucceed()
{
@@ -1046,10 +1060,16 @@ public void ParseDocumentWithJsonSchemaReferencesWorks()
var actualSchema = result.OpenApiDocument.Paths["/users/{userId}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema;
var expectedSchema = new JsonSchemaBuilder()
- .Ref("#/components/schemas/User");
+ .Ref("#/components/schemas/User")
+ .Type(SchemaValueType.Object)
+ .Properties(
+ ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer)),
+ ("username", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("email", new JsonSchemaBuilder().Type(SchemaValueType.String)))
+ .Build();
// Assert
- Assert.Equal(expectedSchema, actualSchema);
+ actualSchema.Should().BeEquivalentTo(expectedSchema);
}
[Fact]
@@ -1099,9 +1119,9 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds()
.Format("int32")
.Default(10),
Reference = new OpenApiReference
- {
- Id = "LimitParameter",
- Type = ReferenceType.Parameter
+ {
+ Id = "LimitParameter",
+ Type = ReferenceType.Parameter
}
}
],
@@ -1126,7 +1146,7 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds()
.Default(10)
}
}
- }
+ }
};
var expectedSerializedDoc = @"openapi: 3.0.1
@@ -1163,6 +1183,7 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds()
// Assert
actualParam.Should().BeEquivalentTo(expectedParam, options => options.Excluding(x => x.Reference.HostDocument));
outputDoc.Should().BeEquivalentTo(expectedSerializedDoc.MakeLineBreaksEnvironmentNeutral());
+
}
- }
+ }
}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs
index ee3dfe97f..5a6e9fd41 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs
@@ -11,6 +11,7 @@
using Microsoft.OpenApi.Reader;
using Xunit;
using Microsoft.OpenApi.Reader.V3;
+using Microsoft.OpenApi.Services;
namespace Microsoft.OpenApi.Readers.Tests.V3Tests
{
@@ -325,6 +326,8 @@ public void ParseParameterWithReferenceWorks()
}
};
+ document.Workspace.RegisterComponents(document);
+
using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "parameterWithRef.yaml"));
var node = TestHelper.CreateYamlMapNode(stream);
diff --git a/test/Microsoft.OpenApi.SmokeTests/GraphTests.cs b/test/Microsoft.OpenApi.SmokeTests/GraphTests.cs
index 8e2344fc1..4527f1016 100644
--- a/test/Microsoft.OpenApi.SmokeTests/GraphTests.cs
+++ b/test/Microsoft.OpenApi.SmokeTests/GraphTests.cs
@@ -52,11 +52,7 @@ public GraphTests(ITestOutputHelper output)
public void LoadOpen()
{
var operations = new[] { "foo", "bar" };
- var workspace = new OpenApiWorkspace();
- workspace.AddDocument(graphOpenApiUrl, _graphOpenApi);
var subset = new OpenApiDocument();
- workspace.AddDocument("subset", subset);
-
Assert.NotNull(_graphOpenApi);
}
}
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs
index 38a39beae..3a16f4d2a 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiCallbackReferenceTests.cs
@@ -9,6 +9,7 @@
using Microsoft.OpenApi.Models.References;
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
+using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Writers;
using VerifyXunit;
using Xunit;
@@ -18,11 +19,14 @@ namespace Microsoft.OpenApi.Tests.Models.References
[Collection("DefaultSettings")]
public class OpenApiCallbackReferenceTests
{
+ // OpenApi doc with external $ref
private const string OpenApi = @"
openapi: 3.0.0
info:
title: Callback with ref Example
version: 1.0.0
+servers:
+ - url: https://myserver.com/v1.0
paths:
/register:
post:
@@ -57,33 +61,16 @@ public class OpenApiCallbackReferenceTests
example: 2531329f-fb09-4ef7-887e-84e648214436
callbacks:
myEvent:
- $ref: '#/components/callbacks/callbackEvent'
-components:
- callbacks:
- callbackEvent:
- '{$request.body#/callbackUrl}':
- post:
- requestBody: # Contents of the callback message
- required: true
- content:
- application/json:
- schema:
- type: object
- properties:
- message:
- type: string
- example: Some event happened
- required:
- - message
- responses:
- '200':
- description: ok";
+ $ref: 'https://myserver.com/beta#/components/callbacks/callbackEvent'";
+ // OpenApi doc with local $ref
private const string OpenApi_2 = @"
openapi: 3.0.0
info:
title: Callback with ref Example
version: 1.0.0
+servers:
+ - url: https://myserver.com/beta
paths:
/register:
post:
@@ -119,30 +106,57 @@ public class OpenApiCallbackReferenceTests
callbacks:
myEvent:
$ref: '#/components/callbacks/callbackEvent'
-";
- private readonly OpenApiCallbackReference _localCallbackReference;
+components:
+ callbacks:
+ callbackEvent:
+ '{$request.body#/callbackUrl}':
+ post:
+ requestBody: # Contents of the callback message
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: Some event happened
+ required:
+ - message
+ responses:
+ '200':
+ description: ok";
+
private readonly OpenApiCallbackReference _externalCallbackReference;
+ private readonly OpenApiCallbackReference _localCallbackReference;
public OpenApiCallbackReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- OpenApiDocument openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- OpenApiDocument openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- openApiDoc_2.Workspace = new();
- openApiDoc_2.Workspace.AddDocument("http://localhost/callbackreference", openApiDoc);
- _localCallbackReference = new("callbackEvent", openApiDoc);
- _externalCallbackReference = new("callbackEvent", openApiDoc_2, "http://localhost/callbackreference");
+ OpenApiDocument openApiDoc = OpenApiDocument.Parse(OpenApi, OpenApiConstants.Yaml).OpenApiDocument;
+ 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);
+ _externalCallbackReference = new("callbackEvent", openApiDoc, "https://myserver.com/beta");
+ _localCallbackReference = new("callbackEvent", openApiDoc_2);
}
[Fact]
public void CallbackReferenceResolutionWorks()
{
// Assert
- Assert.NotEmpty(_localCallbackReference.PathItems);
+ // External reference resolution works
Assert.NotEmpty(_externalCallbackReference.PathItems);
- Assert.Equal("{$request.body#/callbackUrl}", _localCallbackReference.PathItems.First().Key.Expression);
+ Assert.Single(_externalCallbackReference.PathItems);
Assert.Equal("{$request.body#/callbackUrl}", _externalCallbackReference.PathItems.First().Key.Expression);
+ Assert.Equal(OperationType.Post, _externalCallbackReference.PathItems.FirstOrDefault().Value.Operations.FirstOrDefault().Key);;
+
+ // Local reference resolution works
+ Assert.NotEmpty(_localCallbackReference.PathItems);
+ Assert.Single(_localCallbackReference.PathItems);
+ Assert.Equal("{$request.body#/callbackUrl}", _localCallbackReference.PathItems.First().Key.Expression);
+ Assert.Equal(OperationType.Post, _localCallbackReference.PathItems.FirstOrDefault().Value.Operations.FirstOrDefault().Key); ;
}
[Theory]
@@ -152,10 +166,10 @@ public async Task SerializeCallbackReferenceAsV3JsonWorks(bool produceTerseOutpu
{
// Arrange
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
- var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true });
+ var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true });
// Act
- _localCallbackReference.SerializeAsV3(writer);
+ _externalCallbackReference.SerializeAsV3(writer);
writer.Flush();
// Assert
@@ -169,10 +183,10 @@ public async Task SerializeCallbackReferenceAsV31JsonWorks(bool produceTerseOutp
{
// Arrange
var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture);
- var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineLocalReferences = true });
+ var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput, InlineExternalReferences = true });
// Act
- _localCallbackReference.SerializeAsV31(writer);
+ _externalCallbackReference.SerializeAsV31(writer);
writer.Flush();
// Assert
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
index 8d9c12611..d3d85c6b5 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,6 +1,6 @@
{
- "summary": "Example of a user",
- "description": "This is is an example of a user",
+ "summary": "Example of a local user",
+ "description": "This is an example of a local user",
"value": [
{
"id": 1,
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
index c1549bf7c..0c1962929 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"summary":"Example of a user","description":"This is is an example of a user","value":[{"id":1,"name":"John Doe"}]}
\ No newline at end of file
+{"summary":"Example of a local user","description":"This is an example of a local user","value":[{"id":1,"name":"John Doe"}]}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
index 8d9c12611..d3d85c6b5 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,6 +1,6 @@
{
- "summary": "Example of a user",
- "description": "This is is an example of a user",
+ "summary": "Example of a local user",
+ "description": "This is an example of a local user",
"value": [
{
"id": 1,
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
index c1549bf7c..0c1962929 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.SerializeExampleReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"summary":"Example of a user","description":"This is is an example of a user","value":[{"id":1,"name":"John Doe"}]}
\ No newline at end of file
+{"summary":"Example of a local user","description":"This is an example of a local user","value":[{"id":1,"name":"John Doe"}]}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs
index a48ffd906..28a91aa8e 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs
@@ -10,6 +10,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -18,11 +19,14 @@ namespace Microsoft.OpenApi.Tests.Models.References
[Collection("DefaultSettings")]
public class OpenApiExampleReferenceTests
{
+ // OpenApi doc with external $ref
private const string OpenApi = @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
get:
@@ -35,32 +39,39 @@ public class OpenApiExampleReferenceTests
schema:
type: array
items:
- $ref: '#/components/schemas/User'
+ $ref: 'https://myserver.com/beta#/components/schemas/User'
examples:
- - $ref: '#/components/examples/UserExample'
+ - $ref: 'https://myserver.com/beta#/components/examples/UserExample'
components:
- schemas:
- User:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- examples:
- UserExample:
- summary: Example of a user
- description: This is is an example of a user
- value:
- - id: 1
- name: John Doe
+ callbacks:
+ callbackEvent:
+ '{$request.body#/callbackUrl}':
+ post:
+ requestBody: # Contents of the callback message
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: Some event happened
+ required:
+ - message
+ responses:
+ '200':
+ description: ok"";
";
+ // OpenApi doc with local $ref
private const string OpenApi_2 = @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/beta
paths:
/users:
get:
@@ -76,6 +87,22 @@ public class OpenApiExampleReferenceTests
$ref: '#/components/schemas/User'
examples:
- $ref: '#/components/examples/UserExample'
+components:
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+ examples:
+ UserExample:
+ summary: Example of a user
+ description: This is is an example of a user
+ value:
+ - id: 1
+ name: John Doe
";
private readonly OpenApiExampleReference _localExampleReference;
@@ -86,18 +113,18 @@ public class OpenApiExampleReferenceTests
public OpenApiExampleReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/examplereference", _openApiDoc);
+ _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);
- _localExampleReference = new OpenApiExampleReference("UserExample", _openApiDoc)
+ _localExampleReference = new OpenApiExampleReference("UserExample", _openApiDoc_2)
{
Summary = "Example of a local user",
Description = "This is an example of a local user"
};
- _externalExampleReference = new OpenApiExampleReference("UserExample", _openApiDoc_2, "http://localhost/examplereference")
+ _externalExampleReference = new OpenApiExampleReference("UserExample", _openApiDoc, "https://myserver.com/beta")
{
Summary = "Example of an external user",
Description = "This is an example of an external user"
@@ -108,18 +135,19 @@ public OpenApiExampleReferenceTests()
public void ExampleReferenceResolutionWorks()
{
// Assert
+ Assert.NotNull(_localExampleReference.Value);
+ Assert.Equal("[{\"id\":1,\"name\":\"John Doe\"}]", _localExampleReference.Value.Node.ToJsonString());
Assert.Equal("Example of a local user", _localExampleReference.Summary);
Assert.Equal("This is an example of a local user", _localExampleReference.Description);
- Assert.NotNull(_localExampleReference.Value);
- Assert.Equal("Example of an external user", _externalExampleReference.Summary);
- Assert.Equal("This is an example of an external user", _externalExampleReference.Description);
Assert.NotNull(_externalExampleReference.Value);
+ Assert.Equal("Example of an external user", _externalExampleReference.Summary);
+ Assert.Equal("This is an example of an external user", _externalExampleReference.Description);
// The main description and summary values shouldn't change
- Assert.Equal("Example of a user", _openApiDoc.Components.Examples.First().Value.Summary);
+ Assert.Equal("Example of a user", _openApiDoc_2.Components.Examples.First().Value.Summary);
Assert.Equal("This is is an example of a user",
- _openApiDoc.Components.Examples.First().Value.Description);
+ _openApiDoc_2.Components.Examples.FirstOrDefault().Value.Description);
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
index 8bd613186..b957bd951 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
@@ -1,4 +1,4 @@
-{
- "description": "The URL of the newly created post",
+{
+ "description": "Location of the locally referenced post",
"type": "string"
}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
index 9d510cb80..17f59471d 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"description":"The URL of the newly created post","type":"string"}
\ No newline at end of file
+{"description":"Location of the locally referenced post","type":"string"}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
index f43e25a40..badfda7f7 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,5 +1,5 @@
{
- "description": "The URL of the newly created post",
+ "description": "Location of the locally referenced post",
"schema": {
"type": "string"
}
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
index 1b29be17d..cf7cf9e25 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"description":"The URL of the newly created post","schema":{"type":"string"}}
\ No newline at end of file
+{"description":"Location of the locally referenced post","schema":{"type":"string"}}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
index f43e25a40..badfda7f7 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,5 +1,5 @@
{
- "description": "The URL of the newly created post",
+ "description": "Location of the locally referenced post",
"schema": {
"type": "string"
}
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
index 1b29be17d..cf7cf9e25 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.SerializeHeaderReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"description":"The URL of the newly created post","schema":{"type":"string"}}
\ No newline at end of file
+{"description":"Location of the locally referenced post","schema":{"type":"string"}}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs
index 74d8e5797..e55acf5f3 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs
@@ -5,11 +5,13 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using Json.Schema;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Models.References;
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -18,11 +20,14 @@ namespace Microsoft.OpenApi.Tests.Models.References
[Collection("DefaultSettings")]
public class OpenApiHeaderReferenceTests
{
+ // OpenApi doc with external $ref
private const string OpenApi= @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
post:
@@ -32,20 +37,26 @@ public class OpenApiHeaderReferenceTests
description: Post created successfully
headers:
Location:
- $ref: '#/components/headers/LocationHeader'
+ $ref: 'https://myserver.com/beta##/components/headers/LocationHeader'
components:
- headers:
- LocationHeader:
- description: The URL of the newly created post
- schema:
- type: string
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
";
+ // OpenApi doc with local $ref
private const string OpenApi_2 = @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/beta
paths:
/users:
post:
@@ -56,6 +67,12 @@ public class OpenApiHeaderReferenceTests
headers:
Location:
$ref: '#/components/headers/LocationHeader'
+components:
+ headers:
+ LocationHeader:
+ description: The URL of the newly created post
+ schema:
+ type: string
";
private readonly OpenApiHeaderReference _localHeaderReference;
@@ -66,19 +83,19 @@ public class OpenApiHeaderReferenceTests
public OpenApiHeaderReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/headerreference", _openApiDoc);
+ _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);
- _localHeaderReference = new OpenApiHeaderReference("LocationHeader", _openApiDoc)
+ _localHeaderReference = new OpenApiHeaderReference("LocationHeader", _openApiDoc_2)
{
- Description = "Location of the locally created post"
+ Description = "Location of the locally referenced post"
};
- _externalHeaderReference = new OpenApiHeaderReference("LocationHeader", _openApiDoc_2, "http://localhost/headerreference")
+ _externalHeaderReference = new OpenApiHeaderReference("LocationHeader", _openApiDoc, "https://myserver.com/beta")
{
- Description = "Location of the external created post"
+ Description = "Location of the externally referenced post"
};
}
@@ -86,10 +103,11 @@ public OpenApiHeaderReferenceTests()
public void HeaderReferenceResolutionWorks()
{
// Assert
- Assert.Equal("Location of the locally created post", _localHeaderReference.Description);
- Assert.Equal("Location of the external created post", _externalHeaderReference.Description);
+ Assert.Equal(SchemaValueType.String, _externalHeaderReference.Schema.GetJsonType());
+ Assert.Equal("Location of the locally referenced post", _localHeaderReference.Description);
+ Assert.Equal("Location of the externally referenced post", _externalHeaderReference.Description);
Assert.Equal("The URL of the newly created post",
- _openApiDoc.Components.Headers.First().Value.Description); // The main description value shouldn't change
+ _openApiDoc_2.Components.Headers.First().Value.Description); // The main description value shouldn't change
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
index 6fe727ea0..89319843f 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
@@ -3,5 +3,5 @@
"parameters": {
"userId": "$response.body#/id"
},
- "description": "The id value returned in the response can be used as the userId parameter in GET /users/{userId}"
+ "description": "Use the id returned as the userId in `GET /users/{userId}`"
}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
index e3df412e9..93208a391 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"The id value returned in the response can be used as the userId parameter in GET /users/{userId}"}
\ No newline at end of file
+{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"Use the id returned as the userId in `GET /users/{userId}`"}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
index 6fe727ea0..89319843f 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
@@ -3,5 +3,5 @@
"parameters": {
"userId": "$response.body#/id"
},
- "description": "The id value returned in the response can be used as the userId parameter in GET /users/{userId}"
+ "description": "Use the id returned as the userId in `GET /users/{userId}`"
}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
index e3df412e9..93208a391 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.SerializeLinkReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"The id value returned in the response can be used as the userId parameter in GET /users/{userId}"}
\ No newline at end of file
+{"operationId":"getUser","parameters":{"userId":"$response.body#/id"},"description":"Use the id returned as the userId in `GET /users/{userId}`"}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs
index 9a52b5234..87d2db06e 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiLinkReferenceTests.cs
@@ -10,6 +10,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -18,11 +19,14 @@ namespace Microsoft.OpenApi.Tests.Models.References
[Collection("DefaultSettings")]
public class OpenApiLinkReferenceTests
{
+ // OpenApi doc with external $ref
private const string OpenApi = @"
openapi: 3.0.0
info:
version: 0.0.0
title: Links example
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
post:
@@ -49,20 +53,26 @@ public class OpenApiLinkReferenceTests
description: ID of the created user.
links:
GetUserByUserId:
- $ref: '#/components/links/GetUserByUserId' # <---- referencing the link here
+ $ref: 'https://myserver.com/beta#/components/links/GetUserByUserId' # <---- referencing the link here (externally)
components:
- links:
- GetUserByUserId:
- operationId: getUser
- parameters:
- userId: '$response.body#/id'
- description: The id value returned in the response can be used as the userId parameter in GET /users/{userId}";
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+";
+ // OpenApi doc with local $ref
private const string OpenApi_2 = @"
openapi: 3.0.0
info:
version: 0.0.0
title: Links example
+servers:
+ - url: https://myserver.com/beta
paths:
/users:
post:
@@ -90,6 +100,21 @@ public class OpenApiLinkReferenceTests
links:
GetUserByUserId:
$ref: '#/components/links/GetUserByUserId' # <---- referencing the link here
+components:
+ links:
+ GetUserByUserId:
+ operationId: getUser
+ parameters:
+ userId: '$response.body#/id'
+ description: The id value returned in the response can be used as the userId parameter in GET /users/{userId}
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
";
private readonly OpenApiLinkReference _localLinkReference;
@@ -100,17 +125,17 @@ public class OpenApiLinkReferenceTests
public OpenApiLinkReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/linkreferencesample", _openApiDoc);
+ _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);
- _localLinkReference = new("GetUserByUserId", _openApiDoc)
+ _localLinkReference = new("GetUserByUserId", _openApiDoc_2)
{
Description = "Use the id returned as the userId in `GET /users/{userId}`"
};
- _externalLinkReference = new("GetUserByUserId", _openApiDoc_2, "http://localhost/linkreferencesample")
+ _externalLinkReference = new("GetUserByUserId", _openApiDoc, "https://myserver.com/beta")
{
Description = "Externally referenced: Use the id returned as the userId in `GET /users/{userId}`"
};
@@ -120,12 +145,17 @@ public OpenApiLinkReferenceTests()
public void LinkReferenceResolutionWorks()
{
// Assert
- Assert.Equal("Use the id returned as the userId in `GET /users/{userId}`", _localLinkReference.Description);
Assert.Equal("getUser", _localLinkReference.OperationId);
Assert.Equal("userId", _localLinkReference.Parameters.First().Key);
+ Assert.Equal("Use the id returned as the userId in `GET /users/{userId}`", _localLinkReference.Description);
+
+ Assert.Equal("getUser", _externalLinkReference.OperationId);
+ Assert.Equal("userId", _localLinkReference.Parameters.First().Key);
Assert.Equal("Externally referenced: Use the id returned as the userId in `GET /users/{userId}`", _externalLinkReference.Description);
+
+ // The main description and summary values shouldn't change
Assert.Equal("The id value returned in the response can be used as the userId parameter in GET /users/{userId}",
- _openApiDoc.Components.Links.First().Value.Description); // The main description value shouldn't change
+ _openApiDoc_2.Components.Links.FirstOrDefault().Value.Description); // The main description value shouldn't change
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
index 992c2f047..2a64ba6d9 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt
@@ -1,7 +1,7 @@
{
"in": "query",
"name": "limit",
- "description": "Number of results to return",
+ "description": "Results to return",
"type": "integer",
"maximum": 100,
"minimum": 1
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
index 995eb077e..8d3cb1803 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"in":"query","name":"limit","description":"Number of results to return","type":"integer","maximum":100,"minimum":1}
\ No newline at end of file
+{"in":"query","name":"limit","description":"Results to return","type":"integer","maximum":100,"minimum":1}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
index f0066344e..237298009 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,7 +1,8 @@
{
"name": "limit",
"in": "query",
- "description": "Number of results to return",
+ "description": "Results to return",
+ "style": "form",
"schema": {
"maximum": 100,
"minimum": 1,
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
index 2b7ff1cfb..e8eac1b64 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"name":"limit","in":"query","description":"Number of results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}}
\ No newline at end of file
+{"name":"limit","in":"query","description":"Results to return","style":"form","schema":{"maximum":100,"minimum":1,"type":"integer"}}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
index f0066344e..237298009 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,7 +1,8 @@
{
"name": "limit",
"in": "query",
- "description": "Number of results to return",
+ "description": "Results to return",
+ "style": "form",
"schema": {
"maximum": 100,
"minimum": 1,
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
index 2b7ff1cfb..e8eac1b64 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.SerializeParameterReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"name":"limit","in":"query","description":"Number of results to return","schema":{"maximum":100,"minimum":1,"type":"integer"}}
\ No newline at end of file
+{"name":"limit","in":"query","description":"Results to return","style":"form","schema":{"maximum":100,"minimum":1,"type":"integer"}}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs
index 8f76fc526..c00db94f5 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiParameterReferenceTests.cs
@@ -10,6 +10,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -18,37 +19,42 @@ namespace Microsoft.OpenApi.Tests.Models.References
[Collection("DefaultSettings")]
public class OpenApiParameterReferenceTests
{
+ // OpenApi doc with external $ref
private const string OpenApi = @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
get:
summary: Get users
parameters:
- - $ref: '#/components/parameters/limitParam'
+ - $ref: 'https://myserver.com/beta#/components/parameters/limitParam'
responses:
200:
description: Successful operation
components:
- parameters:
- limitParam:
- name: limit
- in: query
- description: Number of results to return
- schema:
- type: integer
- minimum: 1
- maximum: 100
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
";
+ // OpenApi doc with local $ref
private const string OpenApi_2 = @"
openapi: 3.0.0
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/beta
paths:
/users:
get:
@@ -58,6 +64,16 @@ public class OpenApiParameterReferenceTests
responses:
200:
description: Successful operation
+components:
+ parameters:
+ limitParam:
+ name: limit
+ in: query
+ description: Number of results to return
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
";
private readonly OpenApiParameterReference _localParameterReference;
private readonly OpenApiParameterReference _externalParameterReference;
@@ -67,17 +83,17 @@ public class OpenApiParameterReferenceTests
public OpenApiParameterReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/parameterreference", _openApiDoc);
+ _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);
- _localParameterReference = new("limitParam", _openApiDoc)
+ _localParameterReference = new("limitParam", _openApiDoc_2)
{
Description = "Results to return"
};
- _externalParameterReference = new OpenApiParameterReference("limitParam", _openApiDoc_2, "http://localhost/parameterreference")
+ _externalParameterReference = new OpenApiParameterReference("limitParam", _openApiDoc, "https://myserver.com/beta")
{
Description = "Externally referenced: Results to return"
};
@@ -89,9 +105,10 @@ public void ParameterReferenceResolutionWorks()
// Assert
Assert.Equal("limit", _localParameterReference.Name);
Assert.Equal("Results to return", _localParameterReference.Description);
+ Assert.Equal("limit", _externalParameterReference.Name);
Assert.Equal("Externally referenced: Results to return", _externalParameterReference.Description);
Assert.Equal("Number of results to return",
- _openApiDoc.Components.Parameters.First().Value.Description); // The main description value shouldn't change
+ _openApiDoc_2.Components.Parameters.First().Value.Description); // The main description value shouldn't change
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
index 844f5ee81..4aa3a9451 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=False.verified.txt
@@ -1,6 +1,6 @@
{
- "summary": "User path item summary",
- "description": "User path item description",
+ "summary": "Local reference: User path item summary",
+ "description": "Local reference: User path item description",
"get": {
"summary": "Get users",
"responses": {
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
index f43044ef8..1b04eaa44 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.SerializePathItemReferenceAsV31JsonWorks_produceTerseOutput=True.verified.txt
@@ -1 +1 @@
-{"summary":"User path item summary","description":"User path item description","get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}}}
\ No newline at end of file
+{"summary":"Local reference: User path item summary","description":"Local reference: User path item description","get":{"summary":"Get users","responses":{"200":{"description":"Successful operation"}}},"post":{"summary":"Create a user","responses":{"201":{"description":"User created successfully"}}},"delete":{"summary":"Delete a user","responses":{"204":{"description":"User deleted successfully"}}}}
\ No newline at end of file
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs
index d4aba67c3..2d7354f78 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiPathItemReferenceTests.cs
@@ -10,6 +10,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -23,10 +24,32 @@ public class OpenApiPathItemReferenceTests
info:
title: Sample API
version: 1.0.0
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
- $ref: '#/components/pathItems/userPathItem'
+ $ref: 'https://myserver.com/beta#/components/pathItems/userPathItem'
+components:
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+";
+ private const string OpenApi_2 = @"
+openapi: 3.1.0
+info:
+ title: Sample API
+ version: 1.0.0
+servers:
+ - url: https://myserver.com/beta
+paths:
+ /users:
+ $ref: '#/components/pathItems/userPathItem'
components:
pathItems:
userPathItem:
@@ -49,16 +72,6 @@ public class OpenApiPathItemReferenceTests
description: User deleted successfully
";
- private const string OpenApi_2 = @"
-openapi: 3.1.0
-info:
- title: Sample API
- version: 1.0.0
-paths:
- /users:
- $ref: '#/components/pathItems/userPathItem'
-";
-
private readonly OpenApiPathItemReference _localPathItemReference;
private readonly OpenApiPathItemReference _externalPathItemReference;
private readonly OpenApiDocument _openApiDoc;
@@ -67,18 +80,19 @@ public class OpenApiPathItemReferenceTests
public OpenApiPathItemReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/pathitemreference", _openApiDoc);
+ _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);
- _localPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc)
+ _localPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc_2)
{
Description = "Local reference: User path item description",
Summary = "Local reference: User path item summary"
};
- _externalPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc_2, "http://localhost/pathitemreference")
+ _externalPathItemReference = new OpenApiPathItemReference("userPathItem", _openApiDoc, "https://myserver.com/beta")
{
Description = "External reference: User path item description",
Summary = "External reference: User path item summary"
@@ -89,18 +103,20 @@ public OpenApiPathItemReferenceTests()
public void PathItemReferenceResolutionWorks()
{
// Assert
+ Assert.Equal([OperationType.Get, OperationType.Post, OperationType.Delete],
+ _localPathItemReference.Operations.Select(o => o.Key));
Assert.Equal(3, _localPathItemReference.Operations.Count);
Assert.Equal("Local reference: User path item description", _localPathItemReference.Description);
Assert.Equal("Local reference: User path item summary", _localPathItemReference.Summary);
- Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Post, OperationType.Delete },
- _localPathItemReference.Operations.Select(o => o.Key));
+ Assert.Equal([OperationType.Get, OperationType.Post, OperationType.Delete],
+ _externalPathItemReference.Operations.Select(o => o.Key));
Assert.Equal("External reference: User path item description", _externalPathItemReference.Description);
Assert.Equal("External reference: User path item summary", _externalPathItemReference.Summary);
// The main description and summary values shouldn't change
- Assert.Equal("User path item description", _openApiDoc.Components.PathItems.First().Value.Description);
- Assert.Equal("User path item summary", _openApiDoc.Components.PathItems.First().Value.Summary);
+ Assert.Equal("User path item description", _openApiDoc_2.Components.PathItems.First().Value.Description);
+ Assert.Equal("User path item summary", _openApiDoc_2.Components.PathItems.First().Value.Summary);
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs
index dd417f093..b6467d1c1 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System.Globalization;
@@ -12,6 +12,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -25,34 +26,26 @@ public class OpenApiRequestBodyReferenceTests
info:
title: Sample API
version: 1.0.0
-
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
post:
summary: Create a user
requestBody:
- $ref: '#/components/requestBodies/UserRequest' # <---- referencing the requestBody here
+ $ref: 'https://myserver.com/beta#/components/requestBodies/UserRequest' # <---- externally referencing the requestBody here
responses:
'201':
description: User created
-
components:
- requestBodies:
- UserRequest:
- description: User creation request body
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/UserSchema'
-
schemas:
- UserSchema:
+ User:
type: object
properties:
+ id:
+ type: integer
name:
- type: string
- email:
- type: string
+ type: string
";
private readonly string OpenApi_2 = @"
@@ -60,7 +53,8 @@ public class OpenApiRequestBodyReferenceTests
info:
title: Sample API
version: 1.0.0
-
+servers:
+ - url: https://myserver.com/beta
paths:
/users:
post:
@@ -70,6 +64,22 @@ public class OpenApiRequestBodyReferenceTests
responses:
'201':
description: User created
+components:
+ requestBodies:
+ UserRequest:
+ description: User creation request body
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UserSchema'
+ schemas:
+ UserSchema:
+ type: object
+ properties:
+ name:
+ type: string
+ email:
+ type: string
";
private readonly OpenApiRequestBodyReference _localRequestBodyReference;
@@ -80,22 +90,40 @@ public class OpenApiRequestBodyReferenceTests
public OpenApiRequestBodyReferenceTests()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/requestbodyreference", _openApiDoc);
+ _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);
- _localRequestBodyReference = new("UserRequest", _openApiDoc)
+ _localRequestBodyReference = new("UserRequest", _openApiDoc_2)
{
Description = "User request body"
};
- _externalRequestBodyReference = new("UserRequest", _openApiDoc_2, "http://localhost/requestbodyreference")
+ _externalRequestBodyReference = new("UserRequest", _openApiDoc, "https://myserver.com/beta")
{
Description = "External Reference: User request body"
};
}
+ [Fact]
+ public void RequestBodyReferenceResolutionWorks()
+ {
+ // Assert
+ var localContent = _localRequestBodyReference.Content.Values.FirstOrDefault();
+ Assert.NotNull(localContent);
+ Assert.Equal("#/components/schemas/UserSchema", localContent.Schema.GetRef().OriginalString);
+ Assert.Equal("User request body", _localRequestBodyReference.Description);
+ Assert.Equal("application/json", _localRequestBodyReference.Content.First().Key);
+
+ var externalContent = _externalRequestBodyReference.Content.Values.FirstOrDefault();
+ Assert.NotNull(externalContent);
+ Assert.Equal("#/components/schemas/UserSchema", externalContent.Schema.GetRef().OriginalString);
+
+ Assert.Equal("External Reference: User request body", _externalRequestBodyReference.Description);
+ Assert.Equal("User creation request body", _openApiDoc_2.Components.RequestBodies.First().Value.Description);
+ }
+
[Theory]
[InlineData(true)]
[InlineData(false)]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs
index f460374a8..42d0532e7 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs
@@ -11,6 +11,7 @@
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Services;
using VerifyXunit;
using Xunit;
@@ -24,22 +25,14 @@ public class OpenApiResponseReferenceTest
info:
title: Sample API
version: 1.0.0
-
+servers:
+ - url: https://myserver.com/v1.0
paths:
/ping:
get:
responses:
'200':
- $ref: '#/components/responses/OkResponse'
-
-components:
- responses:
- OkResponse:
- description: OK
- content:
- text/plain:
- schema:
- $ref: '#/components/schemas/Pong'
+ $ref: 'https://myserver.com/beta#/components/responses/OkResponse'
";
private const string OpenApi_2 = @"
@@ -47,13 +40,28 @@ public class OpenApiResponseReferenceTest
info:
title: Sample API
version: 1.0.0
-
+servers:
+ - url: https://myserver.com/beta
paths:
/ping:
get:
responses:
'200':
$ref: '#/components/responses/OkResponse'
+components:
+ responses:
+ OkResponse:
+ description: OK
+ content:
+ text/plain:
+ schema:
+ $ref: '#/components/schemas/Pong'
+ schemas:
+ Pong:
+ type: object
+ properties:
+ sound:
+ type: string
";
private readonly OpenApiResponseReference _localResponseReference;
@@ -64,17 +72,17 @@ public class OpenApiResponseReferenceTest
public OpenApiResponseReferenceTest()
{
OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
- _openApiDoc = OpenApiDocument.Parse(OpenApi, "yaml").OpenApiDocument;
- _openApiDoc_2 = OpenApiDocument.Parse(OpenApi_2, "yaml").OpenApiDocument;
- _openApiDoc_2.Workspace = new();
- _openApiDoc_2.Workspace.AddDocument("http://localhost/responsereference", _openApiDoc);
+ _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);
- _localResponseReference = new("OkResponse", _openApiDoc)
+ _localResponseReference = new("OkResponse", _openApiDoc_2)
{
Description = "OK response"
};
- _externalResponseReference = new("OkResponse", _openApiDoc_2, "http://localhost/responsereference")
+ _externalResponseReference = new("OkResponse", _openApiDoc, "https://myserver.com/beta")
{
Description = "External reference: OK response"
};
@@ -84,11 +92,17 @@ public OpenApiResponseReferenceTest()
public void ResponseReferenceResolutionWorks()
{
// Assert
+ var localContent = _localResponseReference.Content.FirstOrDefault();
+ Assert.Equal("text/plain", localContent.Key);
+ Assert.Equal("#/components/schemas/Pong", localContent.Value.Schema.GetRef().OriginalString);
Assert.Equal("OK response", _localResponseReference.Description);
- Assert.Equal("text/plain", _localResponseReference.Content.First().Key);
- Assert.NotNull(_localResponseReference.Content.First().Value.Schema.GetRef());
+
+ var externalContent = _externalResponseReference.Content.FirstOrDefault();
+ Assert.Equal("text/plain", externalContent.Key);
+ Assert.Equal("#/components/schemas/Pong", externalContent.Value.Schema.GetRef().OriginalString);
Assert.Equal("External reference: OK response", _externalResponseReference.Description);
- Assert.Equal("OK", _openApiDoc.Components.Responses.First().Value.Description);
+
+ Assert.Equal("OK", _openApiDoc_2.Components.Responses.First().Value.Description);
}
[Theory]
diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs
index dccd41692..7fcd7dfd8 100644
--- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiSecuritySchemeReferenceTests.cs
@@ -22,7 +22,8 @@ public class OpenApiSecuritySchemeReferenceTests
info:
title: Sample API
version: 1.0.0
-
+servers:
+ - url: https://myserver.com/v1.0
paths:
/users:
get:
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index 8cce0b6f5..a9e086061 100755
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -451,6 +451,7 @@ namespace Microsoft.OpenApi.Models
public const string AuthorizationCode = "authorizationCode";
public const string AuthorizationUrl = "authorizationUrl";
public const string BasePath = "basePath";
+ public const string BaseRegistryUri = "https://openapi.net/";
public const string Basic = "basic";
public const string Bearer = "bearer";
public const string BearerFormat = "bearerFormat";
@@ -618,12 +619,12 @@ namespace Microsoft.OpenApi.Models
public System.Collections.Generic.IDictionary Webhooks { get; set; }
public Microsoft.OpenApi.Services.OpenApiWorkspace Workspace { get; set; }
public Json.Schema.JsonSchema FindSubschema(Json.Pointer.JsonPointer pointer, Json.Schema.EvaluationOptions options) { }
+ public Json.Schema.JsonSchema ResolveJsonSchemaReference(System.Uri referenceUri) { }
public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { }
public System.Collections.Generic.IEnumerable ResolveReferences() { }
public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
- public void SetHostDocument() { }
public static string GenerateHashValue(Microsoft.OpenApi.Models.OpenApiDocument doc) { }
public static Microsoft.OpenApi.Reader.ReadResult Load(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { }
public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.Stream stream, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { }
@@ -1405,28 +1406,6 @@ namespace Microsoft.OpenApi.Services
public OpenApiReferenceError(Microsoft.OpenApi.Exceptions.OpenApiException exception) { }
public OpenApiReferenceError(Microsoft.OpenApi.Models.OpenApiReference reference, string message) { }
}
- public class OpenApiReferenceResolver : Microsoft.OpenApi.Services.OpenApiVisitorBase
- {
- public OpenApiReferenceResolver(Microsoft.OpenApi.Models.OpenApiDocument currentDocument, bool resolveRemoteReferences = true) { }
- public System.Collections.Generic.IEnumerable Errors { get; }
- public Json.Schema.JsonSchema ResolveJsonSchemaReference(System.Uri reference, string description = null, string summary = null) { }
- public override void Visit(Json.Schema.IBaseDocument document) { }
- public override void Visit(ref Json.Schema.JsonSchema schema) { }
- public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceable referenceable) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiComponents components) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiDocument doc) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiOperation operation) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiParameter parameter) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses responses) { }
- public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { }
- public override void Visit(System.Collections.Generic.IDictionary callbacks) { }
- public override void Visit(System.Collections.Generic.IDictionary examples) { }
- public override void Visit(System.Collections.Generic.IDictionary headers) { }
- public override void Visit(System.Collections.Generic.IDictionary links) { }
- public override void Visit(System.Collections.Generic.IDictionary webhooks) { }
- public override void Visit(System.Collections.Generic.IList parameters) { }
- }
public class OpenApiUrlTreeNode
{
public static readonly System.Collections.Generic.IReadOnlyDictionary MermaidNodeStyles;
@@ -1508,18 +1487,13 @@ namespace Microsoft.OpenApi.Services
public OpenApiWorkspace() { }
public OpenApiWorkspace(Microsoft.OpenApi.Services.OpenApiWorkspace workspace) { }
public OpenApiWorkspace(System.Uri baseUrl) { }
- public System.Collections.Generic.IEnumerable Artifacts { get; }
public System.Uri BaseUrl { get; }
- public System.Collections.Generic.IEnumerable Documents { get; }
- public System.Collections.Generic.IEnumerable Fragments { get; }
- public void AddArtifact(string location, System.IO.Stream artifact) { }
- public void AddDocument(string location, Microsoft.OpenApi.Models.OpenApiDocument document) { }
- public void AddFragment(string location, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable fragment) { }
- public void AddSchemaFragment(string location, Json.Schema.JsonSchema fragment) { }
+ public void AddDocumentId(string key, System.Uri value) { }
+ public int ComponentsCount() { }
public bool Contains(string location) { }
- public System.IO.Stream GetArtifact(string location) { }
- public Json.Schema.JsonSchema ResolveJsonSchemaReference(System.Uri reference) { }
- public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { }
+ public System.Uri GetDocumentId(string key) { }
+ public bool RegisterComponent(string location, T component) { }
+ public T ResolveReference(string location) { }
}
public class OperationSearch : Microsoft.OpenApi.Services.OpenApiVisitorBase
{
diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs
index 57faaf72f..68cb9057a 100644
--- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs
@@ -14,22 +14,9 @@ namespace Microsoft.OpenApi.Tests
public class OpenApiWorkspaceTests
{
[Fact]
- public void OpenApiWorkspaceCanHoldMultipleDocuments()
+ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument()
{
- var workspace = new OpenApiWorkspace();
-
- workspace.AddDocument("root", new());
- workspace.AddDocument("common", new());
-
- Assert.Equal(2, workspace.Documents.Count());
- }
-
- [Fact]
- public void OpenApiWorkspacesAllowDocumentsToReferenceEachOther()
- {
- var workspace = new OpenApiWorkspace();
-
- workspace.AddDocument("root", new OpenApiDocument()
+ var doc = new OpenApiDocument()
{
Paths = new OpenApiPaths()
{
@@ -56,8 +43,9 @@ public void OpenApiWorkspacesAllowDocumentsToReferenceEachOther()
}
}
}
- });
- workspace.AddDocument("common", new OpenApiDocument()
+ };
+
+ var doc2 = new OpenApiDocument()
{
Components = new OpenApiComponents()
{
@@ -65,8 +53,11 @@ public void OpenApiWorkspacesAllowDocumentsToReferenceEachOther()
["test"] = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("The referenced one").Build()
}
}
- });
- Assert.Equal(2, workspace.Documents.Count());
+ };
+
+ doc.Workspace.RegisterComponents(doc2);
+
+ Assert.Equal(1, doc.Workspace.ComponentsCount());
}
[Fact]
@@ -74,13 +65,12 @@ public void OpenApiWorkspacesCanResolveExternalReferences()
{
var refUri = new Uri("https://everything.json/common#/components/schemas/test");
var workspace = new OpenApiWorkspace();
- var doc = CreateCommonDocument(refUri);
- var location = "common";
-
- workspace.AddDocument(location, doc);
+ var externalDoc = CreateCommonDocument();
+
+ workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]);
- var schema = workspace.ResolveJsonSchemaReference(refUri);
-
+ var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test");
+
Assert.NotNull(schema);
Assert.Equal("The referenced one", schema.GetDescription());
}
@@ -88,10 +78,8 @@ public void OpenApiWorkspacesCanResolveExternalReferences()
[Fact]
public void OpenApiWorkspacesAllowDocumentsToReferenceEachOther_short()
{
- var workspace = new OpenApiWorkspace();
-
var doc = new OpenApiDocument();
- var reference = "#/components/schemas/test";
+ var reference = "common#/components/schemas/test";
doc.CreatePathItem("/", p =>
{
p.Description = "Consumer";
@@ -106,31 +94,14 @@ public void OpenApiWorkspacesAllowDocumentsToReferenceEachOther_short()
);
});
- var refUri = new Uri("https://registry" + reference.Split('#').LastOrDefault());
- workspace.AddDocument("root", doc);
- workspace.AddDocument("common", CreateCommonDocument(refUri));
+ var doc2 = CreateCommonDocument();
+ doc.Workspace.RegisterComponents(doc2);
+ doc2.Workspace.RegisterComponents(doc);
+ doc.Workspace.AddDocumentId("common", doc2.BaseUri);
var errors = doc.ResolveReferences();
Assert.Empty(errors);
-
- var schema = doc.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema;
- //var effectiveSchema = schema.GetEffective(doc);
- //Assert.False(effectiveSchema.UnresolvedReference);
}
-
- [Fact]
- public void OpenApiWorkspacesShouldNormalizeDocumentLocations()
- {
- var workspace = new OpenApiWorkspace();
- workspace.AddDocument("hello", new());
- workspace.AddDocument("hi", new());
-
- Assert.True(workspace.Contains("./hello"));
- Assert.True(workspace.Contains("./foo/../hello"));
- Assert.True(workspace.Contains("file://" + Environment.CurrentDirectory + "/./foo/../hello"));
-
- Assert.False(workspace.Contains("./goodbye"));
- }
-
+
// Enable Workspace to load from any reader, not just streams.
// Test fragments
@@ -145,10 +116,10 @@ public void OpenApiWorkspacesCanResolveReferencesToDocumentFragments()
// Arrange
var workspace = new OpenApiWorkspace();
var schemaFragment = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Schema from a fragment").Build();
- workspace.AddSchemaFragment("fragment", schemaFragment);
+ workspace.RegisterComponent("common#/components/schemas/test", schemaFragment);
// Act
- var schema = workspace.ResolveJsonSchemaReference(new Uri("https://everything.json/common#/components/schemas/test"));
+ var schema = workspace.ResolveReference("common#/components/schemas/test");
// Assert
Assert.NotNull(schema);
@@ -167,21 +138,18 @@ public void OpenApiWorkspacesCanResolveReferencesToDocumentFragmentsWithJsonPoin
{ "header1", new OpenApiHeader() }
}
};
- workspace.AddFragment("fragment", responseFragment);
+
+ workspace.RegisterComponent("headers/header1", responseFragment);
// Act
- var resolvedElement = workspace.ResolveReference(new()
- {
- Id = "headers/header1",
- ExternalResource = "fragment"
- });
+ var resolvedElement = workspace.ResolveReference("headers/header1");
// Assert
- Assert.Same(responseFragment.Headers["header1"], resolvedElement);
+ Assert.Same(responseFragment.Headers["header1"], resolvedElement.Headers["header1"]);
}
// Test artifacts
- private static OpenApiDocument CreateCommonDocument(Uri refUri)
+ private static OpenApiDocument CreateCommonDocument()
{
var doc = new OpenApiDocument()
{
@@ -193,11 +161,6 @@ private static OpenApiDocument CreateCommonDocument(Uri refUri)
}
};
- foreach(var schema in doc.Components.Schemas)
- {
- SchemaRegistry.Global.Register(refUri, schema.Value);
- }
-
return doc;
}
}