Skip to content
This repository was archived by the owner on Nov 11, 2025. It is now read-only.

Commit 4991360

Browse files
Copilotbaywet
andcommitted
Add $self property to OpenApiDocument with serialization/deserialization support
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
1 parent 0a2c16c commit 4991360

4 files changed

Lines changed: 61 additions & 1 deletion

File tree

src/Microsoft.OpenApi/Models/OpenApiConstants.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public static class OpenApiConstants
4040
/// </summary>
4141
public const string JsonSchemaDialect = "jsonSchemaDialect";
4242

43+
/// <summary>
44+
/// Field: $self
45+
/// </summary>
46+
public const string Self = "$self";
47+
4348
/// <summary>
4449
/// Field: Webhooks
4550
/// </summary>

src/Microsoft.OpenApi/Models/OpenApiDocument.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public void RegisterComponents()
4040
/// </summary>
4141
public Uri? JsonSchemaDialect { get; set; }
4242

43+
/// <summary>
44+
/// The URI identifying this document. This MUST be in the form of a URI. (OAI 3.2.0+)
45+
/// </summary>
46+
public Uri? Self { get; set; }
47+
4348
/// <summary>
4449
/// An array of Server Objects, which provide connectivity information to a target server.
4550
/// </summary>
@@ -126,6 +131,7 @@ public OpenApiDocument(OpenApiDocument? document)
126131
Workspace = document?.Workspace != null ? new(document.Workspace) : null;
127132
Info = document?.Info != null ? new(document.Info) : new OpenApiInfo();
128133
JsonSchemaDialect = document?.JsonSchemaDialect ?? JsonSchemaDialect;
134+
Self = document?.Self ?? Self;
129135
Servers = document?.Servers != null ? [.. document.Servers] : null;
130136
Paths = document?.Paths != null ? new(document.Paths) : [];
131137
Webhooks = document?.Webhooks != null ? new Dictionary<string, IOpenApiPathItem>(document.Webhooks) : null;
@@ -200,6 +206,12 @@ private void SerializeAsV3X(IOpenApiWriter writer, string versionString, OpenApi
200206
// jsonSchemaDialect
201207
writer.WriteProperty(OpenApiConstants.JsonSchemaDialect, JsonSchemaDialect?.ToString());
202208

209+
// $self - only for v3.2+
210+
if (version >= OpenApiSpecVersion.OpenApi3_2)
211+
{
212+
writer.WriteProperty(OpenApiConstants.Self, Self?.ToString());
213+
}
214+
203215
SerializeInternal(writer, version, callback);
204216

205217
// webhooks
@@ -218,6 +230,12 @@ private void SerializeAsV3X(IOpenApiWriter writer, string versionString, OpenApi
218230
}
219231
});
220232

233+
// $self as extension for v3.1 and earlier
234+
if (version < OpenApiSpecVersion.OpenApi3_2 && Self is not null)
235+
{
236+
writer.WriteProperty(OpenApiConstants.ExtensionFieldNamePrefix + "oai-" + OpenApiConstants.Self, Self.ToString());
237+
}
238+
221239
writer.WriteEndObject();
222240
}
223241

src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,29 @@ internal static partial class OpenApiV3Deserializer
2121
} /* Version is valid field but we already parsed it */
2222
},
2323
{"info", (o, n, _) => o.Info = LoadInfo(n, o)},
24+
{
25+
"jsonSchemaDialect", (o, n, _) =>
26+
{
27+
var value = n.GetScalarValue();
28+
if (value != null)
29+
{
30+
o.JsonSchemaDialect = new(value, UriKind.Absolute);
31+
}
32+
}
33+
},
34+
{
35+
"$self", (o, n, _) =>
36+
{
37+
var value = n.GetScalarValue();
38+
if (value != null)
39+
{
40+
o.Self = new(value, UriKind.Absolute);
41+
}
42+
}
43+
},
2444
{"servers", (o, n, _) => o.Servers = n.CreateList(LoadServer, o)},
2545
{"paths", (o, n, _) => o.Paths = LoadPaths(n, o)},
46+
{"webhooks", (o, n, _) => o.Webhooks = n.CreateMap(LoadPathItem, o)},
2647
{"components", (o, n, _) => o.Components = LoadComponents(n, o)},
2748
{"tags", (o, n, _) => { if (n.CreateList(LoadTag, o) is {Count:> 0} tags) {o.Tags = new HashSet<OpenApiTag>(tags, OpenApiTagComparer.Instance); } } },
2849
{"externalDocs", (o, n, _) => o.ExternalDocs = LoadExternalDocs(n, o)},
@@ -32,7 +53,21 @@ internal static partial class OpenApiV3Deserializer
3253
private static readonly PatternFieldMap<OpenApiDocument> _openApiPatternFields = new PatternFieldMap<OpenApiDocument>
3354
{
3455
// We have no semantics to verify X- nodes, therefore treat them as just values.
35-
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}
56+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) =>
57+
{
58+
if (p.Equals("x-oai-$self", StringComparison.OrdinalIgnoreCase))
59+
{
60+
var value = n.GetScalarValue();
61+
if (value != null)
62+
{
63+
o.Self = new(value, UriKind.Absolute);
64+
}
65+
}
66+
else
67+
{
68+
o.AddExtension(p, LoadExtension(p, n));
69+
}
70+
}}
3671
};
3772

3873
public static OpenApiDocument LoadOpenApi(RootNode rootNode, Uri location)

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ namespace Microsoft.OpenApi
539539
public const string Security = "security";
540540
public const string SecurityDefinitions = "securityDefinitions";
541541
public const string SecuritySchemes = "securitySchemes";
542+
public const string Self = "$self";
542543
public const string Server = "server";
543544
public const string Servers = "servers";
544545
public const string Style = "style";
@@ -615,6 +616,7 @@ namespace Microsoft.OpenApi
615616
public System.Collections.Generic.IDictionary<string, object>? Metadata { get; set; }
616617
public Microsoft.OpenApi.OpenApiPaths Paths { get; set; }
617618
public System.Collections.Generic.IList<Microsoft.OpenApi.OpenApiSecurityRequirement>? Security { get; set; }
619+
public System.Uri? Self { get; set; }
618620
public System.Collections.Generic.IList<Microsoft.OpenApi.OpenApiServer>? Servers { get; set; }
619621
public System.Collections.Generic.ISet<Microsoft.OpenApi.OpenApiTag>? Tags { get; set; }
620622
public System.Collections.Generic.IDictionary<string, Microsoft.OpenApi.IOpenApiPathItem>? Webhooks { get; set; }

0 commit comments

Comments
 (0)