Skip to content

Commit 5375c9b

Browse files
authored
Add IsOptional support to AcceptsAttribute (#19)
1 parent 198bb80 commit 5375c9b

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

src/GeneratedEndpoints/MinimalApiGenerator.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public sealed class MinimalApiGenerator : IIncrementalGenerator
6060
private const string DescriptionAttributeNamedParameter = "Description";
6161
private const string ResponseTypeAttributeNamedParameter = "ResponseType";
6262
private const string RequestTypeAttributeNamedParameter = "RequestType";
63+
private const string IsOptionalAttributeNamedParameter = "IsOptional";
6364

6465
private const string RequireAuthorizationAttributeName = "RequireAuthorizationAttribute";
6566
private const string RequireAuthorizationAttributeFullyQualifiedName = $"{AttributesNamespace}.{RequireAuthorizationAttributeName}";
@@ -284,6 +285,11 @@ internal sealed class {{AcceptsAttributeName}} : global::System.Attribute
284285
/// </summary>
285286
public global::System.Type RequestType { get; init; } = default!;
286287
288+
/// <summary>
289+
/// Gets a value indicating whether the request body is optional.
290+
/// </summary>
291+
public bool IsOptional { get; init; }
292+
287293
/// <summary>
288294
/// Gets the primary content type accepted by the endpoint.
289295
/// </summary>
@@ -318,6 +324,11 @@ internal sealed class {{AcceptsAttributeName}}<TRequest> : global::System.Attrib
318324
/// </summary>
319325
public global::System.Type RequestType => typeof(TRequest);
320326
327+
/// <summary>
328+
/// Gets a value indicating whether the request body is optional.
329+
/// </summary>
330+
public bool IsOptional { get; init; }
331+
321332
/// <summary>
322333
/// Gets the primary content type accepted by the endpoint.
323334
/// </summary>
@@ -915,6 +926,7 @@ private static void TryAddAcceptsMetadata(
915926
string? requestType = null;
916927
string contentType;
917928
EquatableImmutableArray<string>? additionalContentTypes;
929+
var isOptional = GetNamedBoolValue(attribute, IsOptionalAttributeNamedParameter);
918930

919931
if (attributeClass.IsGenericType && attributeClass.TypeArguments.Length == 1)
920932
{
@@ -942,7 +954,7 @@ private static void TryAddAcceptsMetadata(
942954
}
943955

944956
var acceptsList = accepts ??= new List<AcceptsMetadata>();
945-
acceptsList.Add(new AcceptsMetadata(requestType, contentType, additionalContentTypes));
957+
acceptsList.Add(new AcceptsMetadata(requestType, contentType, additionalContentTypes, isOptional));
946958
}
947959

948960
private static void TryAddProducesMetadata(
@@ -1001,6 +1013,17 @@ private static void TryAddProducesMetadata(
10011013
return null;
10021014
}
10031015

1016+
private static bool GetNamedBoolValue(AttributeData attribute, string namedParameter, bool defaultValue = false)
1017+
{
1018+
foreach (var namedArg in attribute.NamedArguments)
1019+
{
1020+
if (namedArg.Key == namedParameter && namedArg.Value.Value is bool boolValue)
1021+
return boolValue;
1022+
}
1023+
1024+
return defaultValue;
1025+
}
1026+
10041027
private static EquatableImmutableArray<string> MergeUnion(EquatableImmutableArray<string>? existing, IEnumerable<string> values)
10051028
{
10061029
var list = new List<string>();
@@ -1510,6 +1533,10 @@ private static void GenerateMapRequestHandler(StringBuilder source, RequestHandl
15101533
source.Append(accepts.RequestType);
15111534
source.Append('>');
15121535
source.Append('(');
1536+
if (accepts.IsOptional)
1537+
{
1538+
source.Append("isOptional: true, ");
1539+
}
15131540
source.Append(StringLiteral(accepts.ContentType));
15141541
AppendAdditionalContentTypes(source, accepts.AdditionalContentTypes);
15151542
source.Append(')');
@@ -1660,7 +1687,8 @@ private static StringBuilder GetUseEndpointHandlersStringBuilder(ImmutableArray<
16601687
var additionalCost = accepts.AdditionalContentTypes is { Count: > 0 }
16611688
? accepts.AdditionalContentTypes.Value.Sum(ct => 6 + ct.Length)
16621689
: 0;
1663-
cost += 32 + accepts.RequestType.Length + accepts.ContentType.Length + additionalCost;
1690+
var optionalCost = accepts.IsOptional ? 20 : 0;
1691+
cost += 32 + optionalCost + accepts.RequestType.Length + accepts.ContentType.Length + additionalCost;
16641692
}
16651693
}
16661694

@@ -1902,7 +1930,11 @@ private readonly record struct RequestHandlerMetadata(
19021930
bool ExcludeFromDescription
19031931
);
19041932

1905-
private readonly record struct AcceptsMetadata(string RequestType, string ContentType, EquatableImmutableArray<string>? AdditionalContentTypes);
1933+
private readonly record struct AcceptsMetadata(
1934+
string RequestType,
1935+
string ContentType,
1936+
EquatableImmutableArray<string>? AdditionalContentTypes,
1937+
bool IsOptional);
19061938

19071939
private readonly record struct ProducesMetadata(
19081940
string ResponseType,

0 commit comments

Comments
 (0)