Skip to content

Commit c18bed0

Browse files
authored
Docs (#33)
* - further detail each endpoint type within its own endpoint type md file. * - add package info within relevant documents
1 parent 19f01ec commit c18bed0

File tree

9 files changed

+658
-85
lines changed

9 files changed

+658
-85
lines changed

ModEndpoints.sln

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{9FD33E1B-1
5050
ProjectSection(SolutionItems) = preProject
5151
docs\DisablingComponents.md = docs\DisablingComponents.md
5252
docs\EndpointTypes.md = docs\EndpointTypes.md
53+
docs\EndpointTypes_BusinessResultEndpoint.md = docs\EndpointTypes_BusinessResultEndpoint.md
54+
docs\EndpointTypes_MinimalEndpoint.md = docs\EndpointTypes_MinimalEndpoint.md
55+
docs\EndpointTypes_WebResultEndpoint.md = docs\EndpointTypes_WebResultEndpoint.md
56+
docs\EndpointTypes_ServiceEndpoint.md = docs\EndpointTypes_ServiceEndpoint.md
5357
docs\HandlingFiles.md = docs\HandlingFiles.md
5458
docs\IAsyncEnumerableResponse.md = docs\IAsyncEnumerableResponse.md
5559
docs\OpenApiDocumentation.md = docs\OpenApiDocumentation.md

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,21 @@ internal class ListBooks(ServiceDbContext db)
226226
}
227227
```
228228

229-
### Further Reading
229+
### Explore More Features
230230

231-
For more examples, refer to the following:
231+
For documents detailing other features and functionalities, refer to the following:
232232

233233
- [Parameter Binding](./docs/ParameterBinding.md)
234234
- [Request Validation](./docs/RequestValidation.md)
235235
- [Route Groups](./docs/RouteGroups.md)
236236
- [Disabling Components](./docs/DisablingComponents.md)
237237
- [Open API Documentation](./docs/OpenApiDocumentation.md)
238238
- [Handling Files](./docs/HandlingFiles.md)
239-
- [Endpoint Types](./docs/EndpointTypes.md)
239+
- [Endpoint Types](./docs/EndpointTypes.md):
240+
1. [MinimalEndpoint](./docs/EndpointTypes_MinimalEndpoint.md),
241+
2. [WebResultEndpoint](./docs/EndpointTypes_WebResultEndpoint.md),
242+
3. [BusinessResultEndpoint](./docs/EndpointTypes_BusinessResultEndpoint.md),
243+
4. [ServiceEndpoint](./docs/EndpointTypes_ServiceEndpoint.md)
240244
- [Result Pattern Integration](./docs/ResultPatternIntegration.md)
241245
- [IAsyncEnumerable Response](./docs/IAsyncEnumerableResponse.md)
242246
- [WebResultEndpoint Response Mapping](./docs/WebResultEndpointResponseMapping.md)

docs/EndpointTypes.md

Lines changed: 6 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,9 @@
11
# Endpoint Types
22

3-
WebResultEndpoint, BusinessResultEndpoint and ServiceEndpoint, have a 'HandleAsync' method which returns a strongly typed [business result](https://github.com/modabas/ModResults). But they differ in converting these business results into HTTP responses before sending response to client.
3+
There are 4 different endpoint types:
4+
1. [MinimalEndpoint](EndpointTypes_MinimalEndpoint.md) is in `ModEndpoints.Core` package.
5+
2. [WebResultEndpoint](EndpointTypes_WebResultEndpoint.md),
6+
3. [BusinessResultEndpoint](EndpointTypes_BusinessResultEndpoint.md),
7+
4. [ServiceEndpoint](EndpointTypes_ServiceEndpoint.md) are in `ModEndpoints` package.
48

5-
MinimalEndpoint within ModEndpoints.Core package, is closest to barebones Minimal API. Its 'HandleAsync' method support the following types of return values:
6-
7-
- string
8-
- T (Any other type)
9-
- Minimal API IResult based (Including TypedResults with Results<TResult1, TResultN> return value)
10-
11-
See [How to create responses in Minimal API apps](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/responses?view=aspnetcore-8.0) for detailed information. Other features described previously are common for all of them.
12-
13-
Each type of endpoint has various implementations that accept a request model or not, that has a response model or not.
14-
15-
## MinimalEndpoint
16-
17-
A MinimalEndpoint implementation, after handling request, returns the response model.
18-
19-
- **MinimalEndpoint&lt;TRequest, TResponse&gt;**: Has a request model, supports request validation and returns a response model.
20-
- **MinimalEndpoint&lt;TResponse&gt;**: Doesn't have a request model and returns a response model.
21-
- **MinimalEndpointWithStreamingResponse&lt;TRequest, TResponse&gt;**: Has a request model, supports request validation and returns `IAsyncEnumerable<TResponse>`.
22-
- **MinimalEndpointWithStreamingResponse&lt;TResponse&gt;**: Doesn't have a request model and returns `IAsyncEnumerable<TResponse>`.
23-
24-
## WebResultEndpoint
25-
26-
A WebResultEndpoint implementation, after handling request, maps the [business result](https://github.com/modabas/ModResults) of HandleAsync method to a Minimal API IResult depending on the business result type, state and failure type (if any). Mapping behaviour can be modified or replaced with a custom one.
27-
28-
- **WebResultEndpoint&lt;TRequest, TResponse&gt;**: Has a request model, supports request validation and returns a response model as body of Minimal API IResult if successful.
29-
- **WebResultEndpoint&lt;TRequest&gt;**: Has a request model, supports request validation, doesn't have a response model to return within Minimal API IResult.
30-
- **WebResultEndpointWithEmptyRequest&lt;TResponse&gt;**: Doesn't have a request model and returns a response model as body of Minimal API IResult if successful.
31-
- **WebResultEndpointWithEmptyRequest**: Doesn't have a request model, doesn't have a response model to return within Minimal API IResult.
32-
33-
When result returned from handler method is in Ok state, default WebResultEndpoint response mapping behaviour is:
34-
- For an [endpoint without a response model](../samples/ShowcaseWebApi/Features/Books/DeleteBook.cs), return HTTP 204 No Content.
35-
- For an endpoint with a response model, return HTTP 200 OK with response model as body.
36-
37-
Response HTTP success status code can be configured by [calling 'Produces' extension method during configuration](../samples/ShowcaseWebApi/Features/Books/CreateBook.cs) of endpoint with one of the following status codes:
38-
- StatusCodes.Status200OK,
39-
- StatusCodes.Status201Created,
40-
- StatusCodes.Status202Accepted,
41-
- StatusCodes.Status204NoContent,
42-
- StatusCodes.Status205ResetContent
43-
44-
When result returned from handler method is in Failed state, default WebResultEndpoint response mapping will create a Minimal API IResult with a 4XX or 5XX HTTP Status Code depending on the FailureType of [business result](https://github.com/modabas/ModResults).
45-
46-
It is also possible to implement a custom response mapping behaviour for a WebResultEndpoint. To do so:
47-
- Create an IResultToResponseMapper implementation,
48-
- Add it to dependency injection service collection with a string key during app startup,
49-
- Apply ResultToResponseMapper attribute to endpoint classes that will be using custom mapper. Use service registration string key as Name property of attribute.
50-
51-
## BusinessResultEndpoint
52-
53-
A BusinessResultEndpoint implementation, after handling request, encapsulates the [business result](https://github.com/modabas/ModResults) of HandleAsync method in a HTTP 200 Minimal API IResult and sends to client. The [business result](https://github.com/modabas/ModResults) returned may be in Ok or Failed state. This behaviour makes BusinessResultEndpoints more suitable for cases where clients are aware of Result or Result&lt;TValue&gt; implementations.
54-
55-
- **BusinessResultEndpoint&lt;TRequest, TResultValue&gt;**: Has a request model, supports request validation and returns a [Result&lt;TResultValue&gt;](https://github.com/modabas/ModResults) within HTTP 200 IResult.
56-
- **BusinessResultEndpoint&lt;TRequest&gt;**: Has a request model, supports request validation and returns a [Result](https://github.com/modabas/ModResults) within HTTP 200 IResult.
57-
- **BusinessResultEndpointWithEmptyRequest&lt;TResultValue&gt;**: Doesn't have a request model and returns a [Result&lt;TResultValue&gt;](https://github.com/modabas/ModResults) within HTTP 200 IResult.
58-
- **BusinessResultEndpointWithEmptyRequest**: Doesn't have a request model and returns a [Result](https://github.com/modabas/ModResults) within HTTP 200 IResult.
59-
60-
61-
## ServiceEndpoint
62-
63-
This is a very specialized endpoint which is intended to abstract away all HTTP client and request setup, consumption and response handling when used together with its client implementation. Aim is to enable developers to easily consume remote services with a strongly typed request and response model only by sharing said models between the service and client projects.
64-
65-
A ServiceEndpoint implementation, similar to BusinessResultEntpoint, encapsulates the response [business result](https://github.com/modabas/ModResults) of HandleAsync method in a HTTP 200 Minimal API IResult and sends to client. The [business result](https://github.com/modabas/ModResults) returned may be in Ok or Failed state.
66-
67-
- **ServiceEndpoint&lt;TRequest, TResultValue&gt;**: Has a request model, supports request validation and returns a [Result&lt;TResultValue&gt;](https://github.com/modabas/ModResults) within HTTP 200 IResult.
68-
- **ServiceEndpoint&lt;TRequest&gt;**: Has a request model, supports request validation and returns a [Result](https://github.com/modabas/ModResults) within HTTP 200 IResult.
69-
- **ServiceEndpointWithStreamingResponse&lt;TRequest, TResultValue&gt;**: Has a request model, supports request validation and returns `IAsyncEnumerable<StreamingResponseItem<TResultValue>>`.
70-
- **ServiceEndpointWithStreamingResponse&lt;TRequest&gt;**: Has a request model, supports request validation and returns `IAsyncEnumerable<StreamingResponseItem>`.
71-
72-
>**Note**: `StreamingResponseItem` is a specialized type that contains a `Result` object and also Response Type and Id fields. It is used for streaming responses to allow clients to process each item as it arrives.
73-
74-
A ServiceEndpoint has following special traits and constraints:
75-
- A ServiceEndpoint is always registered as a POST method, and its bound pattern is determined accourding to its request type.
76-
- Request model defined for a ServiceEndpoint is bound with [FromBody] attribute.
77-
- A ServiceEndpoint's request must implement either IServiceRequest (for endpoints implementing ServiceEndpoint&lt;TRequest&gt;) or IServiceRequest&lt;TResultValue&gt; (for endpoints implementing ServiceEndpoint&lt;TRequest, TResultValue&gt;)
78-
- A ServiceEndpoint's request is specific to that endpoint. Each endpoint must have its unique request type.
79-
- To utilize the advantages of a ServiceEndpoint over other endpoint types, its request and response models have to be shared with clients and therefore has to be in a seperate class library.
80-
81-
These restrictions enable clients to call ServiceEndpoints by utilizing a specialized message channel resolved from dependency injection, see [ServiceEndpoint Clients](ServiceEndpointClients.md) documentation for details.
9+
Each type of endpoint has various implementations that accept a request model or not, that has a response model or not. Please refer to individual documents for more info about each endpoint.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# BusinessResultEndpoint
2+
3+
>**Package**: `ModEndpoints`
4+
5+
A BusinessResultEndpoint implementation, after handling request, encapsulates the [business result](https://github.com/modabas/ModResults) of HandleAsync method in a HTTP 200 Minimal API IResult and sends to client. The [business result](https://github.com/modabas/ModResults) returned may be in Ok or Failed state. This behaviour makes BusinessResultEndpoints more suitable for cases where clients are aware of Result or Result&lt;TValue&gt; implementations.
6+
7+
Request model (if any) defined for a BusinessResultEndpoint is bound with [AsParameters] attribute.
8+
9+
- **BusinessResultEndpoint&lt;TRequest, TResultValue&gt;**: Has a request model, supports request validation and returns a [Result&lt;TResultValue&gt;](https://github.com/modabas/ModResults) within HTTP 200 IResult.
10+
``` csharp
11+
public record GetStoreByIdRequest(Guid Id);
12+
13+
public record GetStoreByIdResponse(Guid Id, string Name);
14+
15+
internal class GetStoreByIdRequestValidator : AbstractValidator<GetStoreByIdRequest>
16+
{
17+
public GetStoreByIdRequestValidator()
18+
{
19+
RuleFor(x => x.Id).NotEmpty();
20+
}
21+
}
22+
23+
internal class GetStoreById
24+
: BusinessResultEndpoint<GetStoreByIdRequest, GetStoreByIdResponse>
25+
{
26+
protected override void Configure(
27+
EndpointConfigurationBuilder builder,
28+
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
29+
{
30+
builder.MapGet("/{Id}");
31+
}
32+
33+
protected override async Task<Result<GetStoreByIdResponse>> HandleAsync(
34+
GetStoreByIdRequest req,
35+
CancellationToken ct)
36+
{
37+
await Task.CompletedTask; // Simulate async work
38+
39+
return new GetStoreByIdResponse(
40+
Id: req.Id,
41+
Name: "Name 1");
42+
}
43+
}
44+
```
45+
46+
- **BusinessResultEndpoint&lt;TRequest&gt;**: Has a request model, supports request validation and returns a [Result](https://github.com/modabas/ModResults) within HTTP 200 IResult.
47+
``` csharp
48+
public record UpdateStoreRequest(Guid Id, [FromBody] UpdateStoreRequestBody Body);
49+
50+
public record UpdateStoreRequestBody(string Name);
51+
52+
internal class UpdateStoreRequestValidator : AbstractValidator<UpdateStoreRequest>
53+
{
54+
public UpdateStoreRequestValidator()
55+
{
56+
RuleFor(x => x.Id).NotEmpty();
57+
RuleFor(x => x.Body.Name).NotEmpty();
58+
}
59+
}
60+
61+
internal class UpdateStore
62+
: BusinessResultEndpoint<UpdateStoreRequest>
63+
{
64+
protected override void Configure(
65+
EndpointConfigurationBuilder builder,
66+
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
67+
{
68+
builder.MapPut("/{Id}");
69+
}
70+
71+
protected override Task<Result> HandleAsync(
72+
UpdateStoreRequest req,
73+
CancellationToken ct)
74+
{
75+
return Task.FromResult(Result.Ok());
76+
}
77+
}
78+
```
79+
80+
- **BusinessResultEndpointWithEmptyRequest&lt;TResultValue&gt;**: Doesn't have a request model and returns a [Result&lt;TResultValue&gt;](https://github.com/modabas/ModResults) within HTTP 200 IResult.
81+
``` csharp
82+
public record ListStoresResponse(List<ListStoresResponseItem> Stores);
83+
public record ListStoresResponseItem(Guid Id, string Name);
84+
85+
internal class ListStores
86+
: BusinessResultEndpointWithEmptyRequest<ListStoresResponse>
87+
{
88+
protected override void Configure(
89+
EndpointConfigurationBuilder builder,
90+
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
91+
{
92+
builder.MapGet("/");
93+
}
94+
95+
protected override async Task<Result<ListStoresResponse>> HandleAsync(
96+
CancellationToken ct)
97+
{
98+
await Task.CompletedTask; // Simulate async work
99+
100+
return new ListStoresResponse(Stores:
101+
[
102+
new ListStoresResponseItem(Guid.NewGuid(), "Name 1"),
103+
new ListStoresResponseItem(Guid.NewGuid(), "Name 2")
104+
]);
105+
}
106+
}
107+
```
108+
109+
- **BusinessResultEndpointWithEmptyRequest**: Doesn't have a request model and returns a [Result](https://github.com/modabas/ModResults) within HTTP 200 IResult.
110+
``` csharp
111+
internal class ResultEndpointWithEmptyRequest
112+
: BusinessResultEndpointWithEmptyRequest
113+
{
114+
protected override void Configure(
115+
EndpointConfigurationBuilder builder,
116+
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
117+
{
118+
builder.MapDelete("/");
119+
}
120+
121+
protected override async Task<Result> HandleAsync(
122+
CancellationToken ct)
123+
{
124+
await Task.CompletedTask; // Simulate async work
125+
return Result.Ok();
126+
}
127+
}
128+
```

0 commit comments

Comments
 (0)