Skip to content

Commit b052404

Browse files
committed
feat(routing): update EntityDispatcher with two-tier mapper lookup and pluggable tell handler
1 parent 0590bba commit b052404

7 files changed

Lines changed: 45 additions & 26 deletions

File tree

src/TurboHTTP.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,15 +511,22 @@ namespace TurboHTTP.Server
511511
public override int RemotePort { get; set; }
512512
public override System.Threading.Tasks.Task<System.Security.Cryptography.X509Certificates.X509Certificate2?> GetClientCertificateAsync(System.Threading.CancellationToken cancellationToken = default) { }
513513
}
514+
public sealed class TurboEntityAskBuilder
515+
{
516+
public TurboEntityAskBuilder() { }
517+
public TurboHTTP.Server.TurboEntityAskBuilder Produces<TResponse>(System.Func<TurboHTTP.Server.TurboHttpContext, TResponse, Microsoft.AspNetCore.Http.IResult> handler) { }
518+
public TurboHTTP.Server.TurboEntityAskBuilder Response<TResponse>(System.Func<TurboHTTP.Server.TurboHttpContext, TResponse, System.Threading.Tasks.Task> handler) { }
519+
public TurboHTTP.Server.TurboEntityAskBuilder WithTimeout(System.TimeSpan timeout) { }
520+
}
514521
public sealed class TurboEntityBuilder
515522
{
516523
public TurboEntityBuilder(string pattern) { }
517-
public TurboHTTP.Server.TurboEntityBuilder MapResponse<TResponse>(System.Func<TurboHTTP.Server.TurboHttpContext, TResponse, System.Threading.Tasks.Task> mapper) { }
518524
public TurboHTTP.Server.TurboEntityMethodBuilder OnDelete(System.Delegate messageFactory) { }
519525
public TurboHTTP.Server.TurboEntityMethodBuilder OnGet(System.Delegate messageFactory) { }
520526
public TurboHTTP.Server.TurboEntityMethodBuilder OnPatch(System.Delegate messageFactory) { }
521527
public TurboHTTP.Server.TurboEntityMethodBuilder OnPost(System.Delegate messageFactory) { }
522528
public TurboHTTP.Server.TurboEntityMethodBuilder OnPut(System.Delegate messageFactory) { }
529+
public TurboHTTP.Server.TurboEntityBuilder Response<TResponse>(System.Func<TurboHTTP.Server.TurboHttpContext, TResponse, System.Threading.Tasks.Task> mapper) { }
523530
public TurboHTTP.Server.TurboEntityBuilder UseActorRef(System.Func<Akka.Hosting.IReadOnlyActorRegistry, Akka.Actor.IActorRef> actorRefFactory) { }
524531
public TurboHTTP.Server.TurboEntityBuilder UseActorRef(System.Func<System.IServiceProvider, Akka.Actor.IActorRef> factory) { }
525532
public TurboHTTP.Server.TurboEntityBuilder UseActorRef<TActorKey>() { }
@@ -530,9 +537,19 @@ namespace TurboHTTP.Server
530537
}
531538
public sealed class TurboEntityMethodBuilder
532539
{
540+
[System.Obsolete("Use .IsTell() instead")]
533541
public TurboHTTP.Server.TurboEntityMethodBuilder AcceptedResponse() { }
542+
public void Ask(System.Action<TurboHTTP.Server.TurboEntityAskBuilder> configure) { }
543+
public void Tell(System.Action<TurboHTTP.Server.TurboEntityTellBuilder>? configure = null) { }
534544
public TurboHTTP.Server.TurboEntityMethodBuilder WithTimeout(System.TimeSpan timeout) { }
535545
}
546+
public sealed class TurboEntityTellBuilder
547+
{
548+
public TurboEntityTellBuilder() { }
549+
public void Produces(System.Func<TurboHTTP.Server.TurboHttpContext, Microsoft.AspNetCore.Http.IResult> factory) { }
550+
public void Response(int statusCode) { }
551+
public void Response(int statusCode, System.Func<TurboHTTP.Server.TurboHttpContext, System.Threading.Tasks.Task> writer) { }
552+
}
536553
public sealed class TurboHttpContext : Microsoft.AspNetCore.Http.HttpContext
537554
{
538555
public TurboHttpContext(Microsoft.AspNetCore.Http.Features.IFeatureCollection features, TurboHTTP.Server.TurboConnectionInfo connectionInfo, System.IServiceProvider? services, System.Threading.CancellationToken requestAborted, Akka.Streams.IMaterializer materializer) { }

src/TurboHTTP.Tests/Routing/TurboEntityBuilderSpec.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public void Builder_should_accept_custom_resolver()
128128
public void IsTell_should_set_tell_flag_in_config()
129129
{
130130
var builder = new TurboEntityBuilder("/orders/{id}");
131-
builder.OnPost(() => new TestMessage("new")).IsTell();
131+
builder.OnPost(() => new TestMessage("new")).Tell();
132132

133133
var table = new TurboRouteTable();
134134
builder.AddToRouteTable(table);
@@ -141,7 +141,7 @@ public void IsTell_should_set_tell_flag_in_config()
141141
public void IsTell_with_callback_should_register_tell_route()
142142
{
143143
var builder = new TurboEntityBuilder("/orders/{id}");
144-
builder.OnPost(() => new TestMessage("new")).IsTell(tell =>
144+
builder.OnPost(() => new TestMessage("new")).Tell(tell =>
145145
{
146146
tell.Response(204);
147147
});
@@ -157,7 +157,7 @@ public void IsTell_with_callback_should_register_tell_route()
157157
public void IsAsk_should_register_ask_route()
158158
{
159159
var builder = new TurboEntityBuilder("/orders/{id}");
160-
builder.OnGet(() => new TestMessage("get")).IsAsk(ask =>
160+
builder.OnGet(() => new TestMessage("get")).Ask(ask =>
161161
{
162162
ask.Response<TestMessage>((ctx, msg) => Task.CompletedTask);
163163
});
@@ -176,7 +176,7 @@ public void IsAsk_without_handlers_should_throw()
176176
var methodBuilder = builder.OnGet(() => new TestMessage("get"));
177177

178178
Assert.Throws<InvalidOperationException>(() =>
179-
methodBuilder.IsAsk(ask => { }));
179+
methodBuilder.Ask(ask => { }));
180180
}
181181

182182
[Fact(Timeout = 5000)]

src/TurboHTTP.Tests/Streams/Stages/Server/EntityDispatcherSpec.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ private TurboHttpContext CreateTestContext(
6969
var builder = new TurboEntityBuilder("/orders/{id}");
7070
builder.OnGet((TurboHttpContext ctx) => new GetOrder(ctx.Request.RouteValues["id"]!.ToString()!));
7171
builder.UseActorRef<OrderActorKey>();
72-
builder.MapResponse<OrderResult>((ctx, _) =>
72+
builder.Response<OrderResult>((ctx, _) =>
7373
{
7474
ctx.Response.StatusCode = 200;
7575
return Task.CompletedTask;
7676
});
77-
builder.MapResponse<OrderDeleted>((ctx, _) =>
77+
builder.Response<OrderDeleted>((ctx, _) =>
7878
{
7979
ctx.Response.StatusCode = 204;
8080
return Task.CompletedTask;

src/TurboHTTP/Routing/EntityDispatcher.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ private async Task ExecuteAsk(TurboHttpContext ctx, CancellationToken ct)
3939
var message = await _methodConfig.MessageFactory(ctx, ctx.RequestServices);
4040
var response = await actorRef.Ask<object>(message, timeout, ct);
4141

42-
var mapper = _responseMappers.FindMapper(response.GetType());
42+
var mapper = _methodConfig.EndpointMappers?.FindMapper(response.GetType())
43+
?? _responseMappers.FindMapper(response.GetType());
4344
if (mapper is null)
4445
{
4546
ctx.Response.StatusCode = 500;
@@ -77,7 +78,15 @@ private async Task ExecuteTell(TurboHttpContext ctx, CancellationToken cancellat
7778
var actorRef = await ResolveActor(ctx.RequestServices, cancellationToken);
7879
var message = await _methodConfig.MessageFactory(ctx, ctx.RequestServices);
7980
actorRef.Tell(message);
80-
ctx.Response.StatusCode = 202;
81+
82+
if (_methodConfig.TellResponseHandler is not null)
83+
{
84+
await _methodConfig.TellResponseHandler(ctx);
85+
}
86+
else
87+
{
88+
ctx.Response.StatusCode = 202;
89+
}
8190
}
8291
catch (BindingValidationException ex)
8392
{

src/TurboHTTP/Server/TurboEntityBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public TurboEntityMethodBuilder OnDelete(Delegate messageFactory)
3434
public TurboEntityMethodBuilder OnPatch(Delegate messageFactory)
3535
=> AddMethod(HttpMethod.Patch, messageFactory);
3636

37-
public TurboEntityBuilder MapResponse<TResponse>(Func<TurboHttpContext, TResponse, Task> mapper)
37+
public TurboEntityBuilder Response<TResponse>(Func<TurboHttpContext, TResponse, Task> mapper)
3838
{
3939
_responseMappers.Add(mapper);
4040
return this;

src/TurboHTTP/Server/TurboEntityMethodBuilder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal TurboEntityMethodBuilder(Func<TurboHttpContext, IServiceProvider, Value
1515
MessageFactory = messageFactory;
1616
}
1717

18-
public void IsAsk(Action<TurboEntityAskBuilder> configure)
18+
public void Ask(Action<TurboEntityAskBuilder> configure)
1919
{
2020
_isTell = false;
2121
_endpointMappers = null;
@@ -34,7 +34,7 @@ public void IsAsk(Action<TurboEntityAskBuilder> configure)
3434
_timeoutOverride = builder.TimeoutOverride ?? _timeoutOverride;
3535
}
3636

37-
public void IsTell(Action<TurboEntityTellBuilder>? configure = null)
37+
public void Tell(Action<TurboEntityTellBuilder>? configure = null)
3838
{
3939
_isTell = true;
4040
_endpointMappers = null;
@@ -50,7 +50,7 @@ public void IsTell(Action<TurboEntityTellBuilder>? configure = null)
5050
[Obsolete("Use .IsTell() instead")]
5151
public TurboEntityMethodBuilder AcceptedResponse()
5252
{
53-
IsTell();
53+
Tell();
5454
return this;
5555
}
5656

src/TurboHTTP/Server/TurboEntityTellBuilder.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,22 @@ public sealed class TurboEntityTellBuilder
66
{
77
internal Func<TurboHttpContext, Task>? ResponseHandler { get; private set; }
88

9-
public TurboEntityTellBuilder Response(int statusCode)
9+
public void Response(int statusCode)
1010
{
1111
ResponseHandler = ctx =>
1212
{
1313
ctx.Response.StatusCode = statusCode;
1414
return Task.CompletedTask;
1515
};
16-
return this;
1716
}
1817

19-
public TurboEntityTellBuilder Response(int statusCode, Func<TurboHttpContext, Task> writer)
20-
{
21-
ResponseHandler = async ctx =>
18+
public void Response(int statusCode, Func<TurboHttpContext, Task> writer)
19+
=> ResponseHandler = async ctx =>
2220
{
2321
ctx.Response.StatusCode = statusCode;
2422
await writer(ctx);
2523
};
26-
return this;
27-
}
2824

29-
public TurboEntityTellBuilder Produces(Func<TurboHttpContext, IResult> factory)
30-
{
31-
ResponseHandler = async ctx => await factory(ctx).ExecuteAsync(ctx);
32-
return this;
33-
}
34-
}
25+
public void Produces(Func<TurboHttpContext, IResult> factory)
26+
=> ResponseHandler = async ctx => await factory(ctx).ExecuteAsync(ctx);
27+
}

0 commit comments

Comments
 (0)