Skip to content

Commit 4f5ef25

Browse files
committed
docs: update MapTurboEntity examples to new API and fix landing page table
1 parent 8d37607 commit 4f5ef25

10 files changed

Lines changed: 128 additions & 204 deletions

File tree

docs/.vitepress/components/HomePage.vue

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ const activeTab = ref<'client' | 'server'>('client')
382382
383383
.table-wrapper {
384384
overflow-x: auto;
385+
border-radius: 12px;
386+
border: 1px solid var(--vp-c-divider);
385387
}
386388
387389
.comparison table {
@@ -403,40 +405,50 @@ const activeTab = ref<'client' | 'server'>('client')
403405
background: var(--vp-c-bg-soft);
404406
}
405407
408+
.comparison th.highlight {
409+
background: var(--vp-c-bg-soft);
410+
color: var(--vp-c-text-1);
411+
}
412+
406413
.comparison td {
407-
color: var(--vp-c-text-2);
414+
color: var(--vp-c-text-1);
408415
}
409416
410-
.comparison .highlight {
411-
font-weight: 600;
417+
.comparison tbody tr:nth-child(odd) {
418+
background: var(--vp-c-brand-soft);
412419
}
413420
414-
.comparison tr:nth-child(odd) .highlight {
415-
color: var(--vp-c-brand-1);
421+
.comparison tbody tr:nth-child(even) {
422+
background: rgba(139, 92, 246, 0.08);
416423
}
417424
418-
.comparison tr:nth-child(even) .highlight {
419-
color: #8b5cf6;
425+
.dark .comparison tbody tr:nth-child(even) {
426+
background: rgba(167, 139, 250, 0.08);
420427
}
421428
422-
.dark .comparison tr:nth-child(even) .highlight {
423-
color: #a78bfa;
429+
.comparison .highlight {
430+
font-weight: 600;
431+
color: var(--vp-c-text-1);
424432
}
425433
426434
.comparison tbody tr {
427435
transition: background 0.2s;
428436
}
429437
430438
.comparison tbody tr:nth-child(odd):hover {
431-
background: var(--vp-c-brand-soft);
439+
background: rgba(16, 185, 129, 0.22);
440+
}
441+
442+
.dark .comparison tbody tr:nth-child(odd):hover {
443+
background: rgba(52, 211, 153, 0.22);
432444
}
433445
434446
.comparison tbody tr:nth-child(even):hover {
435-
background: rgba(139, 92, 246, 0.08);
447+
background: rgba(139, 92, 246, 0.16);
436448
}
437449
438450
.dark .comparison tbody tr:nth-child(even):hover {
439-
background: rgba(167, 139, 250, 0.08);
451+
background: rgba(167, 139, 250, 0.16);
440452
}
441453
442454
/* Install */

docs/api/entity-gateway.md

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ public static class TurboRoutingExtensions
2626
When no type parameter is provided, entity keys are boxed `object`:
2727

2828
```csharp
29-
app.MapTurboEntity("/users/{id}", builder =>
29+
app.MapTurboEntity("/users/{id}", entity =>
3030
{
31-
builder.OnGet(ctx => new GetUser(ctx.RouteValues["id"]));
31+
entity.UseActorRef<UserActor>();
32+
entity.OnGet((string id) => new GetUser(id));
3233
});
3334
```
3435

@@ -37,13 +38,11 @@ app.MapTurboEntity("/users/{id}", builder =>
3738
Specify a typed key for type safety:
3839

3940
```csharp
40-
app.MapTurboEntity<int>("/orders/{orderId}", builder =>
41+
app.MapTurboEntity<int>("/orders/{orderId}", entity =>
4142
{
42-
builder.OnGet(ctx =>
43-
{
44-
var orderId = (int)ctx.RouteValues["orderId"];
45-
return new GetOrder(orderId);
46-
});
43+
entity.UseResolver<OrderEntityResolver>();
44+
entity.OnGet((int orderId) => new GetOrder(orderId));
45+
entity.OnPost((int orderId, CreateOrderRequest req) => new CreateOrder(orderId, req.Items));
4746
});
4847
```
4948

@@ -88,29 +87,28 @@ public sealed class TurboEntityBuilder
8887
Specify what message to send for each HTTP method:
8988

9089
```csharp
91-
builder.OnGet(ctx => new GetUser(ctx.RouteValues["id"]));
92-
builder.OnPost(ctx => JsonConvert.DeserializeObject<CreateUserRequest>(
93-
Encoding.UTF8.GetString(ctx.Request.Body)));
94-
builder.OnPut(ctx => new UpdateUser(ctx.RouteValues["id"], ctx.Request.Body));
95-
builder.OnDelete(ctx => new DeleteUser(ctx.RouteValues["id"]));
96-
builder.OnPatch(ctx => new PatchUser(ctx.RouteValues["id"], ctx.Request.Body));
90+
entity.OnGet((int id) => new GetUser(id));
91+
entity.OnPost((int id, CreateUserRequest req) => new CreateUser(id, req.Name));
92+
entity.OnPut((int id, UpdateUserRequest req) => new UpdateUser(id, req.Name));
93+
entity.OnDelete((int id) => new DeleteUser(id));
94+
entity.OnPatch((int id, PatchUserRequest req) => new PatchUser(id, req));
9795
```
9896

99-
Each handler receives the `TurboHttpContext` and returns a message to send to the actor.
97+
Each handler receives typed parameters from the route and request body, and returns a message to send to the actor.
10098

10199
### Response Mapping
102100

103101
By default, responses from actors are serialized as JSON. Customize mapping with `MapResponse<T>`:
104102

105103
```csharp
106-
builder.MapResponse<User>(async (context, user) =>
104+
entity.MapResponse<User>(async (context, user) =>
107105
{
108106
context.Response.StatusCode = 200;
109107
context.Response.ContentType = "application/json";
110108
await context.Response.WriteAsJsonAsync(user);
111109
});
112110

113-
builder.MapResponse<ErrorResponse>(async (context, error) =>
111+
entity.MapResponse<ErrorResponse>(async (context, error) =>
114112
{
115113
context.Response.StatusCode = error.StatusCode;
116114
await context.Response.WriteAsJsonAsync(new { error = error.Message });
@@ -123,7 +121,7 @@ Set per-route timeout for actor responses:
123121

124122
```csharp
125123
// Default: 30 seconds
126-
builder.WithTimeout(TimeSpan.FromSeconds(60));
124+
entity.WithTimeout(TimeSpan.FromSeconds(60));
127125
```
128126

129127
If the actor doesn't respond within the timeout, the response is `504 Gateway Timeout`.
@@ -145,7 +143,7 @@ public sealed class TurboEntityMethodBuilder
145143
Respond with `202 Accepted` instead of waiting for the actor's full response:
146144

147145
```csharp
148-
builder.OnPost(ctx => new CreateUser(...))
146+
entity.OnPost((int id, CreateUserRequest req) => new CreateUser(id, req.Name))
149147
.AcceptedResponse();
150148
```
151149

@@ -156,10 +154,10 @@ Useful for long-running operations where you want to return immediately.
156154
Override the route-level timeout for a specific method:
157155

158156
```csharp
159-
builder.OnGet(ctx => new GetUser(...))
157+
entity.OnGet((int id) => new GetUser(id))
160158
.WithTimeout(TimeSpan.FromSeconds(5));
161159

162-
builder.OnPost(ctx => new CreateUser(...))
160+
entity.OnPost((int id, CreateUserRequest req) => new CreateUser(id, req.Name))
163161
.WithTimeout(TimeSpan.FromSeconds(30));
164162
```
165163

@@ -196,9 +194,9 @@ public class OrderActorResolver : IEntityActorResolver
196194
}
197195

198196
// Register it
199-
builder.UseResolver(new OrderActorResolver(orderManagerRef));
197+
entity.UseResolver(new OrderActorResolver(orderManagerRef));
200198
// Or as a type
201-
builder.UseResolver<OrderActorResolver>();
199+
entity.UseResolver<OrderActorResolver>();
202200
```
203201

204202
### 2. ActorRef Factory
@@ -207,13 +205,13 @@ Direct reference to a specific actor:
207205

208206
```csharp
209207
// From dependency injection
210-
builder.UseActorRef((serviceProvider) =>
208+
entity.UseActorRef((serviceProvider) =>
211209
{
212210
return serviceProvider.GetRequiredService<IActorRef>("userActorRef");
213211
});
214212

215213
// From actor registry
216-
builder.UseActorRef((registry) =>
214+
entity.UseActorRef((registry) =>
217215
{
218216
return registry.Resolve<UserActor>();
219217
});
@@ -224,7 +222,7 @@ builder.UseActorRef((registry) =>
224222
Use the type system to locate actors by type:
225223

226224
```csharp
227-
builder.UseActorRef<UserActor>();
225+
entity.UseActorRef<UserActor>();
228226
```
229227

230228
This looks up `UserActor` in the actor registry.
@@ -259,36 +257,20 @@ public class UserActor : ReceiveActor
259257
}
260258

261259
// Route registration
262-
app.MapTurboEntity<int>("/users/{id}", builder =>
260+
app.MapTurboEntity<int>("/users/{id}", entity =>
263261
{
264-
// GET /users/123
265-
builder.OnGet(ctx =>
266-
{
267-
var id = (int)ctx.RouteValues["id"];
268-
return new UserActor.GetUser { Id = id };
269-
});
262+
entity.UseActorRef<UserActor>();
270263

271-
// POST /users (body contains name)
272-
builder.OnPost(async ctx =>
273-
{
274-
var body = await ctx.Request.BodyReader.ReadAsync();
275-
var json = Encoding.UTF8.GetString(body.Buffer);
276-
var req = JsonConvert.DeserializeObject<CreateUserRequest>(json);
277-
return new UserActor.CreateUser { Name = req.Name };
278-
});
264+
entity.OnGet((int id) => new UserActor.GetUser { Id = id });
265+
entity.OnPost((int id, CreateUserRequest req) => new UserActor.CreateUser { Name = req.Name });
279266

280-
// Custom response mapping
281-
builder.MapResponse<UserActor.User>(async (context, user) =>
267+
entity.MapResponse<UserActor.User>(async (context, user) =>
282268
{
283269
context.Response.ContentType = "application/json";
284270
await context.Response.WriteAsJsonAsync(user);
285271
});
286272

287-
// 30-second timeout for responses
288-
builder.WithTimeout(TimeSpan.FromSeconds(30));
289-
290-
// Resolve to the UserActor
291-
builder.UseActorRef<UserActor>();
273+
entity.WithTimeout(TimeSpan.FromSeconds(30));
292274
});
293275
```
294276

@@ -314,7 +296,7 @@ If the actor doesn't respond within the timeout, the response is `504 Gateway Ti
314296
If the actor throws an exception or the message doesn't match a handler, the gateway responds with `500 Internal Server Error`. Use status code routing or custom response mappers to handle errors from the actor:
315297

316298
```csharp
317-
builder.MapResponse<Result<User>>(async (context, result) =>
299+
entity.MapResponse<Result<User>>(async (context, result) =>
318300
{
319301
if (result.IsSuccess)
320302
{
@@ -332,7 +314,7 @@ builder.MapResponse<Result<User>>(async (context, result) =>
332314
Or use a wrapper response type:
333315

334316
```csharp
335-
builder.MapResponse<ApiResponse>(async (context, response) =>
317+
entity.MapResponse<ApiResponse>(async (context, response) =>
336318
{
337319
context.Response.StatusCode = response.StatusCode;
338320
await context.Response.WriteAsJsonAsync(response);

docs/architecture/layers.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,10 @@ Route to Akka.NET actors for stateful request handling:
122122
```csharp
123123
app.MapTurboEntity<int>("/orders/{id:int}", entity =>
124124
{
125-
entity.UseResolver<OrderActorResolver>();
125+
entity.UseActorRef<OrderActor>();
126126
entity.OnGet((int id) => new GetOrder(id));
127-
entity.MapResponse<OrderResponse>(async (ctx, response) =>
128-
{
129-
ctx.Response.StatusCode = 200;
130-
await ctx.Response.WriteAsJsonAsync(response);
131-
});
127+
entity.OnPost((int id, CreateOrderRequest req) => new CreateOrder(id, req.Items));
128+
entity.OnPut((int id, UpdateOrderRequest req) => new UpdateOrder(id, req.Status));
129+
entity.OnDelete((int id) => new CancelOrder(id));
132130
});
133131
```

docs/architecture/server-extending.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,18 @@ services.AddScoped<IEntityActorResolver, UserActorResolver>();
188188
Then dispatch to actors via `MapTurboEntity()`:
189189

190190
```csharp
191-
app.MapTurboEntity<UserActor>("/users/{id}", entityId: ctx => ctx.RouteValues["id"]?.ToString() ?? "");
191+
app.MapTurboEntity<int>("/users/{id}", entity =>
192+
{
193+
entity.UseResolver<UserActorResolver>();
194+
entity.OnGet((int id) => new GetUser(id));
195+
entity.OnPost((int id, CreateUserRequest req) => new CreateUser(id, req.Name));
196+
entity.OnDelete((int id) => new DeleteUser(id));
197+
});
192198
```
193199

194200
The dispatcher automatically:
195-
1. Resolves the actor using `IEntityActorResolver`
196-
2. Sends the `TurboHttpContext` message to the actor
201+
1. Resolves the actor using the configured resolver
202+
2. Sends the mapped message to the actor
197203
3. Waits for the response
198204
4. Sends the response back to the client
199205

docs/client/connection-pooling.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,3 @@ client.Dispose();
113113
::: info How it works
114114
See [Architecture: Request Pipeline](/architecture/pipeline) to understand how this feature fits into the processing pipeline.
115115
:::
116-
```

docs/client/redirects.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,3 @@ catch (RedirectException ex) when (ex.Error == RedirectError.ProtocolDowngrade)
133133
::: info How it works
134134
See [Architecture: Request Pipeline](/architecture/pipeline) to understand how this feature fits into the processing pipeline.
135135
:::
136-
```

0 commit comments

Comments
 (0)