Skip to content

Commit ed6ffa1

Browse files
Merge pull request #2093 from microsoft/fix/parameter-reference
fix: parameter reference proxy design pattern implementation
2 parents 6a96462 + 1006879 commit ed6ffa1

File tree

50 files changed

+533
-501
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+533
-501
lines changed

src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Humanizer.Inflections;
88
using Microsoft.OpenApi.Hidi.Extensions;
99
using Microsoft.OpenApi.Models;
10+
using Microsoft.OpenApi.Models.Interfaces;
1011
using Microsoft.OpenApi.Services;
1112

1213
namespace Microsoft.OpenApi.Hidi.Formatters
@@ -69,13 +70,13 @@ public override void Visit(OpenApiOperation operation)
6970

7071
var operationId = operation.OperationId;
7172
var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type");
72-
if (operationTypeExtension.IsEquals("function"))
73-
operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List<OpenApiParameter>());
73+
if (operationTypeExtension.IsEquals("function") && operation.Parameters is { Count :> 0})
74+
ResolveFunctionParameters(operation.Parameters);
7475

7576
// Order matters. Resolve operationId.
7677
operationId = RemoveHashSuffix(operationId);
7778
if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function"))
78-
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List<OpenApiParameter>());
79+
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List<IOpenApiParameter>());
7980
operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.'));
8081
operationId = ResolveODataCastOperationId(operationId);
8182
operationId = ResolveByRefOperationId(operationId);
@@ -143,7 +144,7 @@ private static string RemoveHashSuffix(string operationId)
143144
return s_hashSuffixRegex.Match(operationId).Value;
144145
}
145146

146-
private static string RemoveKeyTypeSegment(string operationId, IList<OpenApiParameter> parameters)
147+
private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiParameter> parameters)
147148
{
148149
var segments = operationId.SplitByChar('.');
149150
foreach (var parameter in parameters)
@@ -157,9 +158,9 @@ private static string RemoveKeyTypeSegment(string operationId, IList<OpenApiPara
157158
return string.Join('.', segments);
158159
}
159160

160-
private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiParameter> parameters)
161+
private static void ResolveFunctionParameters(IList<IOpenApiParameter> parameters)
161162
{
162-
foreach (var parameter in parameters.Where(static p => p.Content?.Any() ?? false))
163+
foreach (var parameter in parameters.OfType<OpenApiParameter>().Where(static p => p.Content?.Any() ?? false))
163164
{
164165
// Replace content with a schema object of type array
165166
// for structured or collection-valued function parameters
@@ -173,7 +174,6 @@ private static IList<OpenApiParameter> ResolveFunctionParameters(IList<OpenApiPa
173174
}
174175
};
175176
}
176-
return parameters;
177177
}
178178

179179
private void AddAdditionalPropertiesToSchema(OpenApiSchema schema)

src/Microsoft.OpenApi.Hidi/StatsVisitor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal class StatsVisitor : OpenApiVisitorBase
1313
{
1414
public int ParameterCount { get; set; }
1515

16-
public override void Visit(OpenApiParameter parameter)
16+
public override void Visit(IOpenApiParameter parameter)
1717
{
1818
ParameterCount++;
1919
}

src/Microsoft.OpenApi.Workbench/StatsVisitor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal class StatsVisitor : OpenApiVisitorBase
1313
{
1414
public int ParameterCount { get; set; }
1515

16-
public override void Visit(OpenApiParameter parameter)
16+
public override void Visit(IOpenApiParameter parameter)
1717
{
1818
ParameterCount++;
1919
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System.Collections.Generic;
2+
using System.Text.Json.Nodes;
3+
using Microsoft.OpenApi.Interfaces;
4+
5+
namespace Microsoft.OpenApi.Models.Interfaces;
6+
7+
/// <summary>
8+
/// Defines the base properties for the example object.
9+
/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking.
10+
/// </summary>
11+
public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiSerializable, IOpenApiReadOnlyExtensible
12+
{
13+
/// <summary>
14+
/// REQUIRED. The name of the parameter. Parameter names are case sensitive.
15+
/// If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object.
16+
/// If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition SHALL be ignored.
17+
/// For all other cases, the name corresponds to the parameter name used by the in property.
18+
/// </summary>
19+
public string Name { get; }
20+
21+
/// <summary>
22+
/// REQUIRED. The location of the parameter.
23+
/// Possible values are "query", "header", "path" or "cookie".
24+
/// </summary>
25+
public ParameterLocation? In { get; }
26+
27+
/// <summary>
28+
/// Determines whether this parameter is mandatory.
29+
/// If the parameter location is "path", this property is REQUIRED and its value MUST be true.
30+
/// Otherwise, the property MAY be included and its default value is false.
31+
/// </summary>
32+
public bool Required { get; }
33+
34+
/// <summary>
35+
/// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage.
36+
/// </summary>
37+
public bool Deprecated { get; }
38+
39+
/// <summary>
40+
/// Sets the ability to pass empty-valued parameters.
41+
/// This is valid only for query parameters and allows sending a parameter with an empty value.
42+
/// Default value is false.
43+
/// If style is used, and if behavior is n/a (cannot be serialized),
44+
/// the value of allowEmptyValue SHALL be ignored.
45+
/// </summary>
46+
public bool AllowEmptyValue { get; }
47+
48+
/// <summary>
49+
/// Describes how the parameter value will be serialized depending on the type of the parameter value.
50+
/// Default values (based on value of in): for query - form; for path - simple; for header - simple;
51+
/// for cookie - form.
52+
/// </summary>
53+
public ParameterStyle? Style { get; }
54+
55+
/// <summary>
56+
/// When this is true, parameter values of type array or object generate separate parameters
57+
/// for each value of the array or key-value pair of the map.
58+
/// For other types of parameters this property has no effect.
59+
/// When style is form, the default value is true.
60+
/// For all other styles, the default value is false.
61+
/// </summary>
62+
public bool Explode { get; }
63+
64+
/// <summary>
65+
/// Determines whether the parameter value SHOULD allow reserved characters,
66+
/// as defined by RFC3986 :/?#[]@!$&amp;'()*+,;= to be included without percent-encoding.
67+
/// This property only applies to parameters with an in value of query.
68+
/// The default value is false.
69+
/// </summary>
70+
public bool AllowReserved { get; }
71+
72+
/// <summary>
73+
/// The schema defining the type used for the parameter.
74+
/// </summary>
75+
public OpenApiSchema Schema { get; }
76+
77+
/// <summary>
78+
/// Examples of the media type. Each example SHOULD contain a value
79+
/// in the correct format as specified in the parameter encoding.
80+
/// The examples object is mutually exclusive of the example object.
81+
/// Furthermore, if referencing a schema which contains an example,
82+
/// the examples value SHALL override the example provided by the schema.
83+
/// </summary>
84+
public IDictionary<string, IOpenApiExample> Examples { get; }
85+
86+
/// <summary>
87+
/// Example of the media type. The example SHOULD match the specified schema and encoding properties
88+
/// if present. The example object is mutually exclusive of the examples object.
89+
/// Furthermore, if referencing a schema which contains an example,
90+
/// the example value SHALL override the example provided by the schema.
91+
/// To represent examples of media types that cannot naturally be represented in JSON or YAML,
92+
/// a string value can contain the example with escaping where necessary.
93+
/// </summary>
94+
public JsonNode Example { get; }
95+
96+
/// <summary>
97+
/// A map containing the representations for the parameter.
98+
/// The key is the media type and the value describes it.
99+
/// The map MUST only contain one entry.
100+
/// For more complex scenarios, the content property can define the media type and schema of the parameter.
101+
/// A parameter MUST contain either a schema property, or a content property, but not both.
102+
/// When example or examples are provided in conjunction with the schema object,
103+
/// the example MUST follow the prescribed serialization strategy for the parameter.
104+
/// </summary>
105+
public IDictionary<string, OpenApiMediaType> Content { get; }
106+
}

src/Microsoft.OpenApi/Models/OpenApiComponents.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible
2828
public IDictionary<string, OpenApiResponse>? Responses { get; set; } = new Dictionary<string, OpenApiResponse>();
2929

3030
/// <summary>
31-
/// An object to hold reusable <see cref="OpenApiParameter"/> Objects.
31+
/// An object to hold reusable <see cref="IOpenApiParameter"/> Objects.
3232
/// </summary>
33-
public IDictionary<string, OpenApiParameter>? Parameters { get; set; } =
34-
new Dictionary<string, OpenApiParameter>();
33+
public IDictionary<string, IOpenApiParameter>? Parameters { get; set; } =
34+
new Dictionary<string, IOpenApiParameter>();
3535

3636
/// <summary>
3737
/// An object to hold reusable <see cref="OpenApiExample"/> Objects.
@@ -87,7 +87,7 @@ public OpenApiComponents(OpenApiComponents? components)
8787
{
8888
Schemas = components?.Schemas != null ? new Dictionary<string, OpenApiSchema>(components.Schemas) : null;
8989
Responses = components?.Responses != null ? new Dictionary<string, OpenApiResponse>(components.Responses) : null;
90-
Parameters = components?.Parameters != null ? new Dictionary<string, OpenApiParameter>(components.Parameters) : null;
90+
Parameters = components?.Parameters != null ? new Dictionary<string, IOpenApiParameter>(components.Parameters) : null;
9191
Examples = components?.Examples != null ? new Dictionary<string, IOpenApiExample>(components.Examples) : null;
9292
RequestBodies = components?.RequestBodies != null ? new Dictionary<string, OpenApiRequestBody>(components.RequestBodies) : null;
9393
Headers = components?.Headers != null ? new Dictionary<string, IOpenApiHeader>(components.Headers) : null;

src/Microsoft.OpenApi/Models/OpenApiDocument.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ public void SerializeAsV2(IOpenApiWriter writer)
277277

278278
// parameters
279279
var parameters = Components?.Parameters != null
280-
? new Dictionary<string, OpenApiParameter>(Components.Parameters)
281-
: new Dictionary<string, OpenApiParameter>();
280+
? new Dictionary<string, IOpenApiParameter>(Components.Parameters)
281+
: [];
282282

283283
if (Components?.RequestBodies != null)
284284
{
@@ -592,7 +592,7 @@ public bool AddComponent<T>(string id, T componentToRegister)
592592
Components.Schemas.Add(id, openApiSchema);
593593
break;
594594
case OpenApiParameter openApiParameter:
595-
Components.Parameters ??= new Dictionary<string, OpenApiParameter>();
595+
Components.Parameters ??= new Dictionary<string, IOpenApiParameter>();
596596
Components.Parameters.Add(id, openApiParameter);
597597
break;
598598
case OpenApiResponse openApiResponse:

src/Microsoft.OpenApi/Models/OpenApiOperation.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenA
5858
/// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location.
5959
/// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters.
6060
/// </summary>
61-
public IList<OpenApiParameter>? Parameters { get; set; } = new List<OpenApiParameter>();
61+
public IList<IOpenApiParameter>? Parameters { get; set; } = [];
6262

6363
/// <summary>
6464
/// The request body applicable for this operation.
@@ -127,7 +127,7 @@ public OpenApiOperation(OpenApiOperation? operation)
127127
Description = operation?.Description ?? Description;
128128
ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null;
129129
OperationId = operation?.OperationId ?? OperationId;
130-
Parameters = operation?.Parameters != null ? new List<OpenApiParameter>(operation.Parameters) : null;
130+
Parameters = operation?.Parameters != null ? new List<IOpenApiParameter>(operation.Parameters) : null;
131131
RequestBody = operation?.RequestBody != null ? new(operation?.RequestBody) : null;
132132
Responses = operation?.Responses != null ? new(operation?.Responses) : null;
133133
Callbacks = operation?.Callbacks != null ? new Dictionary<string, IOpenApiCallback>(operation.Callbacks) : null;
@@ -235,7 +235,7 @@ public void SerializeAsV2(IOpenApiWriter writer)
235235
// operationId
236236
writer.WriteProperty(OpenApiConstants.OperationId, OperationId);
237237

238-
List<OpenApiParameter> parameters;
238+
List<IOpenApiParameter> parameters;
239239
if (Parameters == null)
240240
{
241241
parameters = [];

0 commit comments

Comments
 (0)