Skip to content

Commit a3a6d08

Browse files
authored
Allow blank, null, string.Empty route pattern (#60)
1 parent a8842cc commit a3a6d08

File tree

4 files changed

+103
-12
lines changed

4 files changed

+103
-12
lines changed

example/ExampleApi/Endpoints/Todos/GetAll/GetAllTodosEndpoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static void Configure(RouteHandlerBuilder builder)
1919
{
2020
builder
2121
.Group<TodoEndpointGroup>()
22-
.Get("/")
22+
.Get()
2323
.WithSummary("Get all todos")
2424
.WithDescription("Retrieves all todos from the store")
2525
.Version(1.0);

src/IeuanWalker.MinimalApi.Endpoints.Generator/Helpers/HttpVerbRouteHelpers.cs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,49 @@ public static (HttpVerb verb, string pattern)? GetVerbAndPattern(this TypeDeclar
8080
{
8181
HttpVerb? verb = ConvertToHttpVerb(verbMemberAccess.Name.Identifier.ValueText);
8282

83+
if (verb is null)
84+
{
85+
return null;
86+
}
87+
88+
if (firstHttpVerbCall.ArgumentList.Arguments.Count == 0)
89+
{
90+
return (verb.Value, string.Empty);
91+
}
92+
8393
// Try to extract the route pattern argument
84-
if (verb is not null && firstHttpVerbCall.ArgumentList.Arguments.Count > 0)
94+
if (firstHttpVerbCall.ArgumentList.Arguments.Count > 0)
8595
{
8696
ArgumentSyntax argument = firstHttpVerbCall.ArgumentList.Arguments[0];
8797

88-
if (argument.Expression is LiteralExpressionSyntax literal && literal.Token.IsKind(SyntaxKind.StringLiteralToken))
98+
if (argument.Expression is LiteralExpressionSyntax literal)
99+
{
100+
if (literal.Token.IsKind(SyntaxKind.NullKeyword))
101+
{
102+
return (verb.Value, string.Empty);
103+
}
104+
105+
if (literal.Token.IsKind(SyntaxKind.StringLiteralToken))
106+
{
107+
return (verb.Value, literal.Token.ValueText);
108+
}
109+
}
110+
else if (argument.Expression is MemberAccessExpressionSyntax memberAccess)
89111
{
90-
return (verb.Value, literal.Token.ValueText);
112+
// Check for string.Empty and String.Empty
113+
if (memberAccess.Expression is PredefinedTypeSyntax predefinedType
114+
&& predefinedType.Keyword.IsKind(SyntaxKind.StringKeyword)
115+
&& memberAccess.Name.Identifier.ValueText == "Empty")
116+
{
117+
return (verb.Value, string.Empty);
118+
}
119+
120+
if (memberAccess.Expression is IdentifierNameSyntax identifierName
121+
&& identifierName.Identifier.ValueText == "String"
122+
&& memberAccess.Name.Identifier.ValueText == "Empty")
123+
{
124+
return (verb.Value, string.Empty);
125+
}
91126
}
92127
}
93128
}

src/IeuanWalker.MinimalApi.Endpoints/Extensions/MapEndpointExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@ public static class MapEndpointExtensions
1010
{
1111
[ExcludeFromCodeCoverage]
1212
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "<Pending>")]
13-
public static RouteHandlerBuilder Get(this RouteHandlerBuilder builder, [StringSyntax("Route")] string pattern)
13+
public static RouteHandlerBuilder Get(this RouteHandlerBuilder builder, [StringSyntax("Route")] string? pattern = null)
1414
{
1515
return builder;
1616
}
1717
[ExcludeFromCodeCoverage]
1818
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "<Pending>")]
19-
public static RouteHandlerBuilder Post(this RouteHandlerBuilder builder, [StringSyntax("Route")] string pattern)
19+
public static RouteHandlerBuilder Post(this RouteHandlerBuilder builder, [StringSyntax("Route")] string? pattern = null)
2020
{
2121
return builder;
2222
}
2323
[ExcludeFromCodeCoverage]
2424
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "<Pending>")]
25-
public static RouteHandlerBuilder Put(this RouteHandlerBuilder builder, [StringSyntax("Route")] string pattern)
25+
public static RouteHandlerBuilder Put(this RouteHandlerBuilder builder, [StringSyntax("Route")] string? pattern = null)
2626
{
2727
return builder;
2828
}
2929
[ExcludeFromCodeCoverage]
3030
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "<Pending>")]
31-
public static RouteHandlerBuilder Patch(this RouteHandlerBuilder builder, [StringSyntax("Route")] string pattern)
31+
public static RouteHandlerBuilder Patch(this RouteHandlerBuilder builder, [StringSyntax("Route")] string? pattern = null)
3232
{
3333
return builder;
3434
}
3535
[ExcludeFromCodeCoverage]
3636
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "<Pending>")]
37-
public static RouteHandlerBuilder Delete(this RouteHandlerBuilder builder, [StringSyntax("Route")] string pattern)
37+
public static RouteHandlerBuilder Delete(this RouteHandlerBuilder builder, [StringSyntax("Route")] string? pattern = null)
3838
{
3939
return builder;
4040
}

tests/IeuanWalker.MinimalApi.Endpoints.Generator.Tests/Helpers/HttpVerbRouteHelpersTests.cs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public static void Configure(RouteHandlerBuilder builder)
156156
}
157157

158158
[Fact]
159-
public void GetVerbAndPattern_WithHttpVerbButNoRoutePattern_ReturnsNull()
159+
public void GetVerbAndPattern_WithHttpVerbButNoRoutePattern_DefaultToEmptyString()
160160
{
161161
// Arrange
162162
const string sourceCode = """
@@ -176,7 +176,63 @@ public static void Configure(RouteHandlerBuilder builder)
176176
(HttpVerb verb, string pattern)? result = typeDeclaration.GetVerbAndPattern("TestEndpoint", diagnostics);
177177

178178
// Assert
179-
result.ShouldBeNull();
179+
result.ShouldNotBeNull();
180+
result.Value.verb.ShouldBe(HttpVerb.Get);
181+
result.Value.pattern.ShouldBe(string.Empty);
182+
diagnostics.ShouldBeEmpty();
183+
}
184+
185+
[Fact]
186+
public void GetVerbAndPattern_WithHttpVerbButStringEmptyPattern_DefaultToEmptyString()
187+
{
188+
// Arrange
189+
const string sourceCode = """
190+
public class TestEndpoint
191+
{
192+
public static void Configure(RouteHandlerBuilder builder)
193+
{
194+
builder.Get(string.Empty);
195+
}
196+
}
197+
""";
198+
199+
TypeDeclarationSyntax typeDeclaration = ParseTypeDeclaration(sourceCode);
200+
List<DiagnosticInfo> diagnostics = [];
201+
202+
// Act
203+
(HttpVerb verb, string pattern)? result = typeDeclaration.GetVerbAndPattern("TestEndpoint", diagnostics);
204+
205+
// Assert
206+
result.ShouldNotBeNull();
207+
result.Value.verb.ShouldBe(HttpVerb.Get);
208+
result.Value.pattern.ShouldBe(string.Empty);
209+
diagnostics.ShouldBeEmpty();
210+
}
211+
212+
[Fact]
213+
public void GetVerbAndPattern_WithHttpVerbButStringEmptyV2Pattern_DefaultToEmptyString()
214+
{
215+
// Arrange
216+
const string sourceCode = """
217+
public class TestEndpoint
218+
{
219+
public static void Configure(RouteHandlerBuilder builder)
220+
{
221+
builder.Get(String.Empty);
222+
}
223+
}
224+
""";
225+
226+
TypeDeclarationSyntax typeDeclaration = ParseTypeDeclaration(sourceCode);
227+
List<DiagnosticInfo> diagnostics = [];
228+
229+
// Act
230+
(HttpVerb verb, string pattern)? result = typeDeclaration.GetVerbAndPattern("TestEndpoint", diagnostics);
231+
232+
// Assert
233+
result.ShouldNotBeNull();
234+
result.Value.verb.ShouldBe(HttpVerb.Get);
235+
result.Value.pattern.ShouldBe(string.Empty);
180236
diagnostics.ShouldBeEmpty();
181237
}
182238

@@ -378,7 +434,7 @@ public static void Configure(RouteHandlerBuilder builder)
378434
var configuredBuilder = builder
379435
.WithName("Test")
380436
.WithSummary("Test endpoint");
381-
437+
382438
configuredBuilder.Post("/test");
383439
}
384440
}

0 commit comments

Comments
 (0)