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

Commit 29273c6

Browse files
committed
Merge branch 'feat/oai-3-2-support' into feat/Add-support-defaultMapping
Signed-off-by: Vincent Biret <[email protected]>
2 parents 39ed5b7 + 292a28b commit 29273c6

21 files changed

+447
-4
lines changed

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,10 @@ public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiRead
4545
/// REQUIRED. OpenId Connect URL to discover OAuth2 configuration values.
4646
/// </summary>
4747
public Uri? OpenIdConnectUrl { get; }
48+
49+
/// <summary>
50+
/// Specifies that a security scheme is deprecated and SHOULD be transitioned out of usage.
51+
/// Note: This field is supported in OpenAPI 3.2.0+. For earlier versions, it will be serialized as x-oai-deprecated extension.
52+
/// </summary>
53+
public bool Deprecated { get; }
4854
}

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: 25 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

@@ -233,6 +251,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
233251
// openapi
234252
writer.WriteProperty(OpenApiConstants.OpenApi, "3.0.4");
235253
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (w, element) => element.SerializeAsV3(w));
254+
255+
// $self as extension for v3.0
256+
if (Self is not null)
257+
{
258+
writer.WriteProperty(OpenApiConstants.ExtensionFieldNamePrefix + "oai-" + OpenApiConstants.Self, Self.ToString());
259+
}
260+
236261
writer.WriteEndObject();
237262
}
238263

src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public class OpenApiSecurityScheme : IOpenApiExtensible, IOpenApiSecurityScheme
3535
/// <inheritdoc/>
3636
public Uri? OpenIdConnectUrl { get; set; }
3737

38+
/// <inheritdoc/>
39+
public bool Deprecated { get; set; }
40+
3841
/// <inheritdoc/>
3942
public IDictionary<string, IOpenApiExtension>? Extensions { get; set; }
4043

@@ -57,6 +60,7 @@ internal OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme)
5760
BearerFormat = securityScheme.BearerFormat ?? BearerFormat;
5861
Flows = securityScheme.Flows != null ? new(securityScheme.Flows) : null;
5962
OpenIdConnectUrl = securityScheme.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null;
63+
Deprecated = securityScheme.Deprecated;
6064
Extensions = securityScheme.Extensions != null ? new Dictionary<string, IOpenApiExtension>(securityScheme.Extensions) : null;
6165
}
6266
/// <summary>
@@ -124,6 +128,19 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
124128
break;
125129
}
126130

131+
// deprecated - serialize as native field for v3.2+ or as extension for earlier versions
132+
if (Deprecated)
133+
{
134+
if (version >= OpenApiSpecVersion.OpenApi3_2)
135+
{
136+
writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);
137+
}
138+
else
139+
{
140+
writer.WriteProperty("x-oai-deprecated", Deprecated, false);
141+
}
142+
}
143+
127144
// extensions
128145
writer.WriteExtensions(Extensions, version);
129146

src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public string? Description
6060
/// <inheritdoc/>
6161
public SecuritySchemeType? Type { get => Target?.Type; }
6262

63+
/// <inheritdoc/>
64+
public bool Deprecated { get => Target?.Deprecated ?? default; }
65+
6366
/// <inheritdoc/>
6467
public override IOpenApiSecurityScheme CopyReferenceAsTargetElementWithOverrides(IOpenApiSecurityScheme source)
6568
{

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,21 @@ internal static partial class OpenApiV3Deserializer
3232
private static readonly PatternFieldMap<OpenApiDocument> _openApiPatternFields = new PatternFieldMap<OpenApiDocument>
3333
{
3434
// 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))}
35+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) =>
36+
{
37+
if (p.Equals("x-oai-$self", StringComparison.OrdinalIgnoreCase))
38+
{
39+
var value = n.GetScalarValue();
40+
if (value != null)
41+
{
42+
o.Self = new(value, UriKind.Absolute);
43+
}
44+
}
45+
else
46+
{
47+
o.AddExtension(p, LoadExtension(p, n));
48+
}
49+
}}
3650
};
3751

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

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,21 @@ internal static partial class OpenApiV3Deserializer
7272
private static readonly PatternFieldMap<OpenApiSecurityScheme> _securitySchemePatternFields =
7373
new()
7474
{
75-
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}
75+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) =>
76+
{
77+
if (p.Equals("x-oai-deprecated", StringComparison.OrdinalIgnoreCase))
78+
{
79+
var deprecated = n.GetScalarValue();
80+
if (deprecated != null)
81+
{
82+
o.Deprecated = bool.Parse(deprecated);
83+
}
84+
}
85+
else
86+
{
87+
o.AddExtension(p, LoadExtension(p,n));
88+
}
89+
}}
7690
};
7791

7892
public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument)

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,21 @@ internal static partial class OpenApiV31Deserializer
3030
private static readonly PatternFieldMap<OpenApiDocument> _openApiPatternFields = new()
3131
{
3232
// We have no semantics to verify X- nodes, therefore treat them as just values.
33-
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}
33+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) =>
34+
{
35+
if (p.Equals("x-oai-$self", StringComparison.OrdinalIgnoreCase))
36+
{
37+
var value = n.GetScalarValue();
38+
if (value != null && Uri.TryCreate(value, UriKind.Absolute, out var self))
39+
{
40+
o.Self = self;
41+
}
42+
}
43+
else
44+
{
45+
o.AddExtension(p, LoadExtension(p, n));
46+
}
47+
}}
3448
};
3549

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

src/Microsoft.OpenApi/Reader/V31/OpenApiSecuritySchemeDeserializer.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,21 @@ internal static partial class OpenApiV31Deserializer
7979
private static readonly PatternFieldMap<OpenApiSecurityScheme> _securitySchemePatternFields =
8080
new()
8181
{
82-
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))}
82+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) =>
83+
{
84+
if (p.Equals("x-oai-deprecated", StringComparison.OrdinalIgnoreCase))
85+
{
86+
var deprecated = n.GetScalarValue();
87+
if (deprecated != null)
88+
{
89+
o.Deprecated = bool.Parse(deprecated);
90+
}
91+
}
92+
else
93+
{
94+
o.AddExtension(p, LoadExtension(p,n));
95+
}
96+
}}
8397
};
8498

8599
public static IOpenApiSecurityScheme LoadSecurityScheme(ParseNode node, OpenApiDocument hostDocument)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal static partial class OpenApiV32Deserializer
1818
},
1919
{"info", (o, n, _) => o.Info = LoadInfo(n, o)},
2020
{"jsonSchemaDialect", (o, n, _) => { if (n.GetScalarValue() is string {} sjsd && Uri.TryCreate(sjsd, UriKind.Absolute, out var jsd)) {o.JsonSchemaDialect = jsd;}} },
21+
{"$self", (o, n, _) => { if (n.GetScalarValue() is string {} sself && Uri.TryCreate(sself, UriKind.Absolute, out var self)) {o.Self = self;}} },
2122
{"servers", (o, n, _) => o.Servers = n.CreateList(LoadServer, o)},
2223
{"paths", (o, n, _) => o.Paths = LoadPaths(n, o)},
2324
{"webhooks", (o, n, _) => o.Webhooks = n.CreateMap(LoadPathItem, o)},

0 commit comments

Comments
 (0)