Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Update README doc samples to latest (#188)
* Update README doc samples to latest

closes #172 .
Also fixed navigation.
Added links to explain OCP and SRP

* Update README.md

closes #171

* Update README.md
  • Loading branch information
idormenco committed Nov 1, 2022
1 parent bd1b256 commit 5515961
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 11 deletions.
24 changes: 15 additions & 9 deletions README.md
Expand Up @@ -60,13 +60,13 @@ For version 3.0 we implemented a new way to define the base classes using "fluen

[7. Related Articles](#7-related-articles)

[8. Videos and Podcasts](#8-videos-podcasts)
[8. Videos and Podcasts](#8-videos-and-podcasts)

[9. Related / Similar Projects](#8-related--similar-projects)
[9. Related / Similar Projects](#9-related--similar-projects)

[10. Projects Using ApiEndpoints](#9-projects-using-apiendpoints)
[10. Projects Using ApiEndpoints](#10-projects-using-apiendpoints)

[11. Success Stories and Testimonials](#10-success-stories-and-testimonials)
[11. Success Stories and Testimonials](#11-success-stories-and-testimonials)

## 1. Motivation

Expand Down Expand Up @@ -97,7 +97,7 @@ Most REST APIs have groups of endpoints for a given resource. In Controller-base
I'll look to add detailed documentation in the future but for now here's all you need to get started (you can also check the sample project):

1. Add the [Ardalis.ApiEndpoints NuGet package](https://www.nuget.org/packages/Ardalis.ApiEndpoints/) to your ASP.NET Core web project.
2. Create Endpoint classes by inheriting from either `BaseEndpoint<TRequest,TResponse>` (for endpoints that accept a model as input) or `BaseEndpoint<TResponse>` (for endpoints that simply return a response). For example, a POST endpoint that creates a resource and then returns the newly created record would use the version that includes both a Request and a Response. A GET endpoint that just returns a list of records and doesn't accept any arguments would use the second version.
2. Create Endpoint classes by inheriting from either `EndpointBaseSync<TRequest,TResponse>` (for endpoints that accept a model as input) or `EndpointBaseSync<TResponse>` (for endpoints that simply return a response). For example, a POST endpoint that creates a resource and then returns the newly created record would use the version that includes both a Request and a Response. A GET endpoint that just returns a list of records and doesn't accept any arguments would use the second version.
3. Implement the base class's abstract `Handle()` method.
4. Make sure to add a `[HttpGet]` or similar attribute to your `Handle()` method, specifying its route.
5. Define your `TResponse` type in a file in the same folder as its corresponding endpoint (or in the same file if you prefer).
Expand Down Expand Up @@ -197,7 +197,7 @@ Below are what I expect will be some common questions:

### How do I use shared routing conventions?

~~If you want to create a common route template for all or some subset of your Endpoints, simply create a BaseEndpoint of your own that inherits from `Ardalis.Api.Endpoints.BaseEndpoint` and add a `[Route]` attribute to it.~~
If you want to create a common route template for all or some subset of your Endpoints, simply create a EndpointBaseSync of your own that inherits from `Ardalis.Api.Endpoints.EndpointBaseSync` and add a `[Route]` attribute to it.

After refactoring to use the fluent generics pattern, there is no longer a way to use a base class for a default route. Instead, you should define your routes as constants which you can store in a central file or in each Request DTO (the sample shows this approach).

Expand Down Expand Up @@ -255,9 +255,15 @@ For more information, take a look at [this discussion](https://github.com/ardali
There's an example in the [sample app](https://github.com/ardalis/ApiEndpoints/blob/main/sample/SampleEndpointApp/Endpoints/Authors/ListJsonFile.cs) that shows how to set this up and return a File actionresult. For the base type, just use the `WithoutResponse` option and in the endpoint handler return `File()`.

### How can I use model binding to pull values from multiple places, like `[FromRoute]`, `[FromBody]`, etc.?

#172
The base endpoints only expose a single model type which is used on the Handle method, so you can't easily add additional parameters to the Handle method. However, you can put as many properties on the associated Request DTO as you want, and model binding allows you to set the same attributes per property as you would have set per parameter on the action method. See [Model Binding Docs](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding) and [discussion here in issue 42](https://github.com/ardalis/ApiEndpoints/issues/42)

### How can I use streaming from server to client?
There's an example in the [sample app](https://github.com/ardalis/ApiEndpoints/blob/main/sample/SampleEndpointApp/Endpoints/Authors/Stream.cs) that shows how to set this up and return an `IAsyncEnumerable<T>`. For the base type, just use the `WithAsyncEnumerableResult<T>` option and in the endpoint handler yeld return after awaiting your async code.

> Note: streaming with IAsyncEnumerable does not work within Swagger Ui. Use curl to test this functionality
> ``` bash
> curl -X "GET" "https://localhost:44338/api/Authors/stream" -H "accept: text/plain"
## 6. Roadmap
The following are some things I'd like to add to the project/package.
Expand All @@ -268,15 +274,15 @@ Visual Studio and/or CLI item templates would make it much easier to create Endp
### Route Conventions
One thing that Controllers do have is built-in support in the framework to use their name in routes (e.g. "/[controller]/{id?}"). Currently in the sample app routes are hard-coded strings. It would be nice if there were an easy way to use a convention based on foldername or namespace or something (using foldername would align with how Razor Pages routing works).
One thing that Controllers do have is built-in support in the framework to use their name in routes (e.g. "`[controller]/{id?}`"). Currently in the sample app routes are hard-coded strings. It would be nice if there were an easy way to use a convention based on foldername or namespace or something (using foldername would align with how Razor Pages routing works).
## 7. Related Articles
- [Moving from Controllers and Actions to Endpoints](https://ardalis.com/moving-from-controllers-and-actions-to-endpoints-with-mediatr)
- [Decoupling Controllers with ApiEndpoints](https://betweentwobrackets.dev/posts/2020/09/decoupling-controllers-with-apiendpoints/)
- [Fluent Generics](https://tyrrrz.me/blog/fluent-generics)
## 8 Videos and Podcasts
## 8. Videos and Podcasts
- [Clean up your .NET Controllers with API Endpoints by Nick Chapsas](https://www.youtube.com/watch?v=SDu0MA6TmuM&ab_channel=NickChapsas)
- [The .NET Docs Show - Controllers are Dinosaurs and the Case for API Endpoints](https://www.youtube.com/watch?v=9oroj2TmxBs&ab_channel=dotNET)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Expand Up @@ -14,7 +14,7 @@ When working with ASP.NET Core API Endpoints your project won't need any Control

Most REST APIs have groups of endpoints for a given resource. In Controller-based projects you would have a controller per resource. When using API Endpoints you can simply create a folder per resource, just as you would use folders to group related pages in Razor Pages.

Instead of Model-View-Controller (MVC) the pattern becomes Request-EndPoint-Response(REPR). The REPR (reaper) pattern is much simpler and groups everything that has to do with a particular API endpoint together. It follows SOLID principles, in particular SRP and OCP. It also has all the benefits of feature folders and better follows the Common Closure Principle by grouping together things that change together.
Instead of Model-View-Controller (MVC) the pattern becomes Request-EndPoint-Response(REPR). The REPR (reaper) pattern is much simpler and groups everything that has to do with a particular API endpoint together. It follows SOLID principles, in particular [SRP](https://en.wikipedia.org/wiki/Single-responsibility_principle) and [OCP](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle). It also has all the benefits of feature folders and better follows the Common Closure Principle by grouping together things that change together.

## Installing Ardalis.ApiEndpoints

Expand Down
2 changes: 1 addition & 1 deletion sample/SampleEndpointApp/README.md
Expand Up @@ -24,4 +24,4 @@ dotnet ef database update

## Duplicate Code in Endpoints

If the duplicate dependency code in the endpoints bothers you, you can avoid it easily by creating your own `BaseAppEndpoint` classes that inherit from `BaseEndpoint`. These can expose as properties any common dependencies like loggers, mappers, or generic repositories, and then use an IOC container's property injection feature to ensure they're always populated when the endpoint is created.
If the duplicate dependency code in the endpoints bothers you, you can avoid it easily by creating your own `AppEndpointBaseSync` classes that inherit from `EndpointBaseSync`. These can expose as properties any common dependencies like loggers, mappers, or generic repositories, and then use an IOC container's property injection feature to ensure they're always populated when the endpoint is created.

0 comments on commit 5515961

Please sign in to comment.