Skip to content

Commit

Permalink
Merge pull request #1769 from captainsafia/property-bag-support
Browse files Browse the repository at this point in the history
Add support for unserializable annotations on OpenAPI document
  • Loading branch information
MaggieKimani1 authored Aug 5, 2024
2 parents d96749f + 2df890a commit 7876018
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 11 deletions.
19 changes: 19 additions & 0 deletions src/Microsoft.OpenApi/Interfaces/IOpenApiAnnotatable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System.Collections.Generic;

namespace Microsoft.OpenApi.Interfaces
{
/// <summary>
/// Represents an Open API element that can be annotated with
/// non-serializable properties in a property bag.
/// </summary>
public interface IOpenApiAnnotatable
{
/// <summary>
/// A collection of properties associated with the current OpenAPI element.
/// </summary>
IDictionary<string, object> Annotations { get; set; }
}
}
6 changes: 5 additions & 1 deletion src/Microsoft.OpenApi/Models/OpenApiDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.OpenApi.Models
/// <summary>
/// Describes an OpenAPI object (OpenAPI document). See: https://swagger.io/specification
/// </summary>
public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible
public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenApiAnnotatable
{
/// <summary>
/// Related workspace containing OpenApiDocuments that are referenced in this document
Expand Down Expand Up @@ -70,6 +70,9 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible
/// </summary>
public string HashCode => GenerateHashValue(this);

/// <inheritdoc />
public IDictionary<string, object> Annotations { get; set; }

/// <summary>
/// Parameter-less constructor
/// </summary>
Expand All @@ -89,6 +92,7 @@ public OpenApiDocument(OpenApiDocument document)
Tags = document?.Tags != null ? new List<OpenApiTag>(document.Tags) : null;
ExternalDocs = document?.ExternalDocs != null ? new(document?.ExternalDocs) : null;
Extensions = document?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(document.Extensions) : null;
Annotations = document?.Annotations != null ? new Dictionary<string, object>(document.Annotations) : null;
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion src/Microsoft.OpenApi/Models/OpenApiOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models
/// <summary>
/// Operation Object.
/// </summary>
public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible
public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenApiAnnotatable
{
/// <summary>
/// Default value for <see cref="Deprecated"/>.
Expand Down Expand Up @@ -105,6 +105,9 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible
/// </summary>
public IDictionary<string, IOpenApiExtension> Extensions { get; set; } = new Dictionary<string, IOpenApiExtension>();

/// <inheritdoc />
public IDictionary<string, object> Annotations { get; set; }

/// <summary>
/// Parameterless constructor
/// </summary>
Expand All @@ -128,6 +131,7 @@ public OpenApiOperation(OpenApiOperation operation)
Security = operation?.Security != null ? new List<OpenApiSecurityRequirement>(operation.Security) : null;
Servers = operation?.Servers != null ? new List<OpenApiServer>(operation.Servers) : null;
Extensions = operation?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(operation.Extensions) : null;
Annotations = operation?.Annotations != null ? new Dictionary<string, object>(operation.Annotations) : null;
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Models
/// <summary>
/// Schema Object.
/// </summary>
public class OpenApiSchema : IOpenApiReferenceable, IEffective<OpenApiSchema>, IOpenApiExtensible
public class OpenApiSchema : IOpenApiReferenceable, IEffective<OpenApiSchema>, IOpenApiExtensible, IOpenApiAnnotatable
{
/// <summary>
/// Follow JSON Schema definition. Short text providing information about the data.
Expand Down Expand Up @@ -241,6 +241,9 @@ public class OpenApiSchema : IOpenApiReferenceable, IEffective<OpenApiSchema>, I
/// </summary>
public OpenApiReference Reference { get; set; }

/// <inheritdoc />
public IDictionary<string, object> Annotations { get; set; }

/// <summary>
/// Parameterless constructor
/// </summary>
Expand Down Expand Up @@ -290,6 +293,7 @@ public OpenApiSchema(OpenApiSchema schema)
Extensions = schema?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(schema.Extensions) : null;
UnresolvedReference = schema?.UnresolvedReference ?? UnresolvedReference;
Reference = schema?.Reference != null ? new(schema?.Reference) : null;
Annotations = schema?.Annotations != null ? new Dictionary<string, object>(schema?.Annotations) : null;
}

/// <summary>
Expand Down
37 changes: 34 additions & 3 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public class OpenApiDocumentTests
{
Type = ReferenceType.Schema,
Id = "schema2"
}
},
Annotations = new Dictionary<string, object> { { "x-foo", "bar" } }
},
["schema2"] = new()
{
Expand All @@ -38,7 +39,8 @@ public class OpenApiDocumentTests
{
["property1"] = new()
{
Type = "string"
Type = "string",
Annotations = new Dictionary<string, object> { { "key1", "value" } }
}
}
},
Expand All @@ -56,9 +58,11 @@ public class OpenApiDocumentTests
{
["property1"] = new()
{
Type = "string"
Type = "string",
Annotations = new Dictionary<string, object> { { "key1", "value" } }
}
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Reference = new()
{
Type = ReferenceType.Schema,
Expand Down Expand Up @@ -100,6 +104,7 @@ public class OpenApiDocumentTests
{
Version = "1.0.0"
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = TopLevelReferencingComponents
};

Expand All @@ -109,6 +114,7 @@ public class OpenApiDocumentTests
{
Version = "1.0.0"
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = TopLevelSelfReferencingComponentsWithOtherProperties
};

Expand All @@ -118,6 +124,7 @@ public class OpenApiDocumentTests
{
Version = "1.0.0"
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = TopLevelSelfReferencingComponents
};

Expand Down Expand Up @@ -509,6 +516,7 @@ public class OpenApiDocumentTests
}
}
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = AdvancedComponentsWithReference
};

Expand Down Expand Up @@ -884,6 +892,7 @@ public class OpenApiDocumentTests
}
}
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = AdvancedComponents
};

Expand Down Expand Up @@ -1272,6 +1281,7 @@ public class OpenApiDocumentTests
}
}
},
Annotations = new Dictionary<string, object> { { "key1", "value" } },
Components = AdvancedComponents
};

Expand Down Expand Up @@ -1827,5 +1837,26 @@ public void SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue()
expected = expected.MakeLineBreaksEnvironmentNeutral();
actual.Should().Be(expected);
}

[Fact]
public void OpenApiDocumentCopyConstructorWithAnnotationsSucceeds()
{
var baseDocument = new OpenApiDocument
{
Annotations = new Dictionary<string, object>
{
["key1"] = "value1",
["key2"] = 2
}
};

var actualDocument = new OpenApiDocument(baseDocument);

Assert.Equal(baseDocument.Annotations["key1"], actualDocument.Annotations["key1"]);

baseDocument.Annotations["key1"] = "value2";

Assert.NotEqual(baseDocument.Annotations["key1"], actualDocument.Annotations["key1"]);
}
}
}
24 changes: 23 additions & 1 deletion test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ public class OpenApiOperationTests
Url = "http://server.com",
Description = "serverDescription"
}
}
},
Annotations = new Dictionary<string, object> { { "key1", "value1" }, { "key2", 2 } },
};

private static readonly OpenApiOperation _advancedOperationWithTagsAndSecurity = new()
Expand Down Expand Up @@ -864,5 +865,26 @@ public void EnsureOpenApiOperationCopyConstructor_SerializationResultsInSame()
actual.Should().Be(expected);
}
}

[Fact]
public void OpenApiOperationCopyConstructorWithAnnotationsSucceeds()
{
var baseOperation = new OpenApiOperation
{
Annotations = new Dictionary<string, object>
{
["key1"] = "value1",
["key2"] = 2
}
};

var actualOperation = new OpenApiOperation(baseOperation);

Assert.Equal(baseOperation.Annotations["key1"], actualOperation.Annotations["key1"]);

baseOperation.Annotations["key1"] = "value2";

Assert.NotEqual(baseOperation.Annotations["key1"], actualOperation.Annotations["key1"]);
}
}
}
24 changes: 23 additions & 1 deletion test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class OpenApiSchemaTests
ExternalDocs = new()
{
Url = new("http://example.com/externalDocs")
}
},
Annotations = new Dictionary<string, object> { { "key1", "value1" }, { "key2", 2 } }
};

public static readonly OpenApiSchema AdvancedSchemaObject = new()
Expand Down Expand Up @@ -483,6 +484,27 @@ public void OpenApiSchemaCopyConstructorSucceeds()
Assert.True(actualSchema.Nullable);
}

[Fact]
public void OpenApiSchemaCopyConstructorWithAnnotationsSucceeds()
{
var baseSchema = new OpenApiSchema
{
Annotations = new Dictionary<string, object>
{
["key1"] = "value1",
["key2"] = 2
}
};

var actualSchema = new OpenApiSchema(baseSchema);

Assert.Equal(baseSchema.Annotations["key1"], actualSchema.Annotations["key1"]);

baseSchema.Annotations["key1"] = "value2";

Assert.NotEqual(baseSchema.Annotations["key1"], actualSchema.Annotations["key1"]);
}

public static TheoryData<IOpenApiAny> SchemaExamples()
{
return new()
Expand Down
13 changes: 10 additions & 3 deletions test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ namespace Microsoft.OpenApi.Interfaces
{
T GetEffective(Microsoft.OpenApi.Models.OpenApiDocument document);
}
public interface IOpenApiAnnotatable
{
System.Collections.Generic.IDictionary<string, object> Annotations { get; set; }
}
public interface IOpenApiElement { }
public interface IOpenApiExtensible : Microsoft.OpenApi.Interfaces.IOpenApiElement
{
Expand Down Expand Up @@ -592,10 +596,11 @@ namespace Microsoft.OpenApi.Models
public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
}
public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
{
public OpenApiDocument() { }
public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument document) { }
public System.Collections.Generic.IDictionary<string, object> Annotations { get; set; }
public Microsoft.OpenApi.Models.OpenApiComponents Components { get; set; }
public System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.Interfaces.IOpenApiExtension> Extensions { get; set; }
public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; }
Expand Down Expand Up @@ -774,11 +779,12 @@ namespace Microsoft.OpenApi.Models
public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
}
public class OpenApiOperation : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
public class OpenApiOperation : Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
{
public const bool DeprecatedDefault = false;
public OpenApiOperation() { }
public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation operation) { }
public System.Collections.Generic.IDictionary<string, object> Annotations { get; set; }
public System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.Models.OpenApiCallback> Callbacks { get; set; }
public bool Deprecated { get; set; }
public string Description { get; set; }
Expand Down Expand Up @@ -900,13 +906,14 @@ namespace Microsoft.OpenApi.Models
public OpenApiResponses() { }
public OpenApiResponses(Microsoft.OpenApi.Models.OpenApiResponses openApiResponses) { }
}
public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IEffective<Microsoft.OpenApi.Models.OpenApiSchema>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
public class OpenApiSchema : Microsoft.OpenApi.Interfaces.IEffective<Microsoft.OpenApi.Models.OpenApiSchema>, Microsoft.OpenApi.Interfaces.IOpenApiAnnotatable, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
{
public OpenApiSchema() { }
public OpenApiSchema(Microsoft.OpenApi.Models.OpenApiSchema schema) { }
public Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; }
public bool AdditionalPropertiesAllowed { get; set; }
public System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AllOf { get; set; }
public System.Collections.Generic.IDictionary<string, object> Annotations { get; set; }
public System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AnyOf { get; set; }
public Microsoft.OpenApi.Any.IOpenApiAny Default { get; set; }
public bool Deprecated { get; set; }
Expand Down

0 comments on commit 7876018

Please sign in to comment.