Skip to content

Commit

Permalink
Merge pull request #1943 from microsoft/mk/add-json-schema-const-keyword
Browse files Browse the repository at this point in the history
Add support for JSON schema `const` keyword in OpenApiSchema
  • Loading branch information
MaggieKimani1 authored Nov 26, 2024
2 parents 5ceb174 + 12ee205 commit 98b01e0
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/Microsoft.OpenApi/Models/OpenApiConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public static class OpenApiConstants
/// </summary>
public const string Title = "title";

/// <summary>
/// Field: Const
/// </summary>
public const string Const = "const";

/// <summary>
/// Field: Type
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiRe
/// </summary>
public virtual JsonSchemaType? Type { get; set; }

/// <summary>
/// Follow JSON Schema definition: https://json-schema.org/draft/2020-12/json-schema-validation
/// </summary>
public virtual string Const { get; set; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// While relying on JSON Schema's defined formats,
Expand Down Expand Up @@ -347,6 +352,7 @@ public OpenApiSchema(OpenApiSchema schema)
{
Title = schema?.Title ?? Title;
Id = schema?.Id ?? Id;
Const = schema?.Const ?? Const;
Schema = schema?.Schema ?? Schema;
Comment = schema?.Comment ?? Comment;
Vocabulary = schema?.Vocabulary != null ? new Dictionary<string, bool>(schema.Vocabulary) : null;
Expand Down Expand Up @@ -563,6 +569,7 @@ internal void WriteV31Properties(IOpenApiWriter writer)
writer.WriteProperty(OpenApiConstants.Id, Id);
writer.WriteProperty(OpenApiConstants.DollarSchema, Schema);
writer.WriteProperty(OpenApiConstants.Comment, Comment);
writer.WriteProperty(OpenApiConstants.Const, Const);
writer.WriteOptionalMap(OpenApiConstants.Vocabulary, Vocabulary, (w, s) => w.WriteValue(s));
writer.WriteOptionalMap(OpenApiConstants.Defs, Definitions, (w, s) => s.SerializeAsV31(w));
writer.WriteProperty(OpenApiConstants.DynamicRef, DynamicRef);
Expand Down
23 changes: 20 additions & 3 deletions src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public class OpenApiSchemaReference : OpenApiSchema
internal OpenApiSchema _target;
private readonly OpenApiReference _reference;
private string _description;
private JsonNode _default;
private JsonNode _example;
private IList<JsonNode> _examples;

private OpenApiSchema Target
{
Expand Down Expand Up @@ -90,6 +93,8 @@ internal OpenApiSchemaReference(OpenApiSchema target, string referenceId)
/// <inheritdoc/>
public override JsonSchemaType? Type { get => Target.Type; set => Target.Type = value; }
/// <inheritdoc/>
public override string Const { get => Target.Const; set => Target.Const = value; }
/// <inheritdoc/>
public override string Format { get => Target.Format; set => Target.Format = value; }
/// <inheritdoc/>
public override string Description
Expand All @@ -114,7 +119,11 @@ public override string Description
/// <inheritdoc/>
public override decimal? MultipleOf { get => Target.MultipleOf; set => Target.MultipleOf = value; }
/// <inheritdoc/>
public override JsonNode Default { get => Target.Default; set => Target.Default = value; }
public override JsonNode Default
{
get => _default ??= Target.Default;
set => _default = value;
}
/// <inheritdoc/>
public override bool ReadOnly { get => Target.ReadOnly; set => Target.ReadOnly = value; }
/// <inheritdoc/>
Expand Down Expand Up @@ -152,9 +161,17 @@ public override string Description
/// <inheritdoc/>
public override OpenApiDiscriminator Discriminator { get => Target.Discriminator; set => Target.Discriminator = value; }
/// <inheritdoc/>
public override JsonNode Example { get => Target.Example; set => Target.Example = value; }
public override JsonNode Example
{
get => _example ??= Target.Example;
set => _example = value;
}
/// <inheritdoc/>
public override IList<JsonNode> Examples { get => Target.Examples; set => Target.Examples = value; }
public override IList<JsonNode> Examples
{
get => _examples ??= Target.Examples;
set => Target.Examples = value;
}
/// <inheritdoc/>
public override IList<JsonNode> Enum { get => Target.Enum; set => Target.Enum = value; }
/// <inheritdoc/>
Expand Down
4 changes: 4 additions & 0 deletions src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ internal static partial class OpenApiV31Deserializer
}
}
},
{
"const",
(o, n, _) => o.Const = n.GetScalarValue()
},
{
"allOf",
(o, n, t) => o.AllOf = n.CreateList(LoadSchema, t)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,5 +452,48 @@ public void SerializeSchemaWithJsonSchemaKeywordsWorks()
schema.Vocabulary.Keys.Count.Should().Be(5);
schemaString.MakeLineBreaksEnvironmentNeutral().Should().Be(expected.MakeLineBreaksEnvironmentNeutral());
}

[Fact]
public void ParseSchemaWithConstWorks()
{
var expected = @"{
""$schema"": ""https://json-schema.org/draft/2020-12/schema"",
""required"": [
""status""
],
""type"": ""object"",
""properties"": {
""status"": {
""const"": ""active"",
""type"": ""string""
},
""user"": {
""required"": [
""role""
],
""type"": ""object"",
""properties"": {
""role"": {
""const"": ""admin"",
""type"": ""string""
}
}
}
}
}";

var path = Path.Combine(SampleFolderPath, "schemaWithConst.json");

// Act
var schema = OpenApiModelFactory.Load<OpenApiSchema>(path, OpenApiSpecVersion.OpenApi3_1, out _);
schema.Properties["status"].Const.Should().Be("active");
schema.Properties["user"].Properties["role"].Const.Should().Be("admin");

// serialization
var writer = new StringWriter();
schema.SerializeAsV31(new OpenApiJsonWriter(writer));
var schemaString = writer.ToString();
schemaString.MakeLineBreaksEnvironmentNeutral().Should().Be(expected.MakeLineBreaksEnvironmentNeutral());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"status": {
"type": "string",
"const": "active"
},
"user": {
"type": "object",
"properties": {
"role": {
"type": "string",
"const": "admin"
}
},
"required": [ "role" ]
}
},
"required": [ "status" ]
}
3 changes: 3 additions & 0 deletions test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ namespace Microsoft.OpenApi.Models
public const string Comment = "$comment";
public const string Components = "components";
public const string ComponentsSegment = "/components/";
public const string Const = "const";
public const string Consumes = "consumes";
public const string Contact = "contact";
public const string Content = "content";
Expand Down Expand Up @@ -882,6 +883,7 @@ namespace Microsoft.OpenApi.Models
public virtual System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AllOf { get; set; }
public virtual System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AnyOf { get; set; }
public virtual string Comment { get; set; }
public virtual string Const { get; set; }
public virtual System.Text.Json.Nodes.JsonNode Default { get; set; }
public virtual System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.Models.OpenApiSchema> Definitions { get; set; }
public virtual bool Deprecated { get; set; }
Expand Down Expand Up @@ -1222,6 +1224,7 @@ namespace Microsoft.OpenApi.Models.References
public override System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AllOf { get; set; }
public override System.Collections.Generic.IList<Microsoft.OpenApi.Models.OpenApiSchema> AnyOf { get; set; }
public override string Comment { get; set; }
public override string Const { get; set; }
public override System.Text.Json.Nodes.JsonNode Default { get; set; }
public override System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.Models.OpenApiSchema> Definitions { get; set; }
public override bool Deprecated { get; set; }
Expand Down

0 comments on commit 98b01e0

Please sign in to comment.