Yes, but `SingleOrDefault` is more efficient without `OfType` , because OfType will try to cast all elements of sequence and return some IEnumerable object, and then you use only single element from this IEnumerable. Results of the simple benchmark with object[3] where only last element is of type: | Method | Mean | Error | StdDev | Gen 0 | Allocated | | OfTypeSingle | 124.15 ns | 2.422 ns | 2.790 ns | 0.0105 | 88 B | | SingleByType | 44.38 ns | 0.920 ns | 0.860 ns | 0.0038 | 32 B |
@@AlFasGD for SingleOrDefault() it requires at least 2 matches, whereas FirstOrDefault() needs 1 match, so you would expect a better perfomance with OfType().FirstOrDefault()
The problem is that FirstOrDefault is dangerous and SingleOrDefault is used intentionally. I want to throw if for some reason two object of the same type have snuck in there. This is a generic method which could be used everywhere so if some endpoint for some reason has two types of the same type I want this to be an exception. FirstOrDefault will hide the problem and cause a bug silently. It should be used VERY carefully.
Nice, this is cool. We've been running validation through a mediatr pipeline then handling the validation exception in middleware to return bad requests. It'll make more sense to short circuit all that overhead and move validation entirely to the API.
Yeah i like MediatR to only handle my domain level validation and have my api level validation on the contract itself as a filter so that's a perfect addition
@@nickchapsas can you please give an example of domain vs contract level validation. i want to understand the need for both, seems most validation will be domain level even simple email address could be considered domain level.
@@zubairahmed3877 For example whether a property is mandatory or not or whether an email looks like an email. That would be api contract validation. Domain validation would check things specific to our application's domain logic, for example if another person with that same email is allowed in the system or not.
@@nickchapsas Does your domain layer generally check the format of the email too? If yes, wouldn't this result in duplicate validation code? I generally never validate on api side as the domain already has rules about data format when creating Value Objects. Is that a bad approach?
@@benjaminb.4043 I go back and forth on email validation. Sometimes it’s in domain only sometimes it’s in both places but that’s a bit of a problem so I tend to only keep it on the domain
So, what we see, is that the webapi approaches are turning more to a functional style of programming. Mediatr is a kind of a wrapper of a function, now these minimal apis and filters, we just combine functions together. Every release we have less OOP and more functional things. I hope some day we'll have an ability to use decriminated unions in C# and this will allow to perfectly describe business logic of the app.
I have the same problem and almost exact the same SDK version (7.0.101). Does anyone know the answer? I use Rider IDE. @edit: Okay I have the answer. It has been renamed to "IEndpointFilter" interface. Similarly, "AddRouteHandlerFilter" method has been replaced with "AddEndpointFilter" etc.
I'm not sure there's much room to look at IDisposable - You want to use it to clean-up unmanaged resources explicitly. Sure, you could wait for the GC to get around to cleaning up the object to call the destructor/finalizer that has your code to clean it up implicitly, but you have no idea when thats going to happen. IDisposable lets you clean up the unmanaged resources immediately leaving only the wrapper on the managed side that the GC has to clean up. (You can disable finalization calls on a Dispose call so the GC won't try to repeat it) You can also use a Using statement to call Dispose implicitly at the end of the scope which is handy for filestreams. Only other instance I have seen for this is relating to events. If a class for example is subscribed to a publisher/event then it will be kept alive/won't be collected until it unsubscribes or until the publisher is cleaned up. Publishers keep subscribers alive, but subscribers don't keep publishers alive. Some people opt for a weak pattern to prevent this.
This is really cool, I'm glad that's a possibility in 7. So the reason why this is not possible earlier, is it because the AddFilter method isn't defined?
A big benefit of filters in MVC is that you can apply them per-controller or per-project. Do you know if that's available (yet) with this approach, or do you literally have to go and add `.Filter()` to every endpoint to do fully cross-cutting concerns (like model validation for instance)?
i have never worked with minimal apis so i dont know if there is a framwork way to do project level filters, but a c# way that comes to mind would be to just write an extension method on the webapplication, so you basically have your own mappost where you already add the filters if you know what i mean
@@nickchapsas yeah the per endpoint are clear but i couldnt find a per project one in this video. maybe im misunderstanding something but all filters shown in the video look like enpoint scoped to me
@@nickchapsas I might be missing something but I'm only seeing AddFilter method used on MapGet, MapPost etc in the video, meaning I would need to call that for all endpoints using the filter. Is there no way to add a generic validation filter for all endpoints? If not that is still a good use case for MediatR since it is possible to do that there.
Filters seem nice. I think pulling the validations from the assembly using reflection is evil voodoo and should be avoided. A clearer pattern would be too map the model validator to the validator filter directly like ValidationFilter where T : IValidator (or whatever the validator interface is) so you could call .AddFilter()
I don't agree that assembly scanning is bad. It is extremely common and the .NET platform is using it extensively behind the scenes and it's something that almost all libraries, like MediatR, AutoMapper, FluentValidation etc have adopted.
@@nickchapsas I know what you mean. I used to write a lot of code like that because it's more convenient and less typing. I've found over the years though that it ends up causing more headaches than it's worth. When it's in the .net framework and the usage is well documented and replicated and explained in tons of tutorials/codebases it's a little bit different. If you're writing code like that in a team, you're essentially adding magic behaviour and it causes issues and confusion. As an example, being able to right click and Find All Usages of a class/interface/method (or a text search) to see where it's being used is invaluable when debugging or refactoring. I can't tell you how often this pattern has burnt all of the different teams I've worked on, but I can say every time it gets implemented it ends up being way more inconvenient in the long run by far. Technical debt at its finest 💸.
@@kelton5020 IT sounds more like poor documentation and commenting is more your issue than magic behaviour. The fact that most large projects and the framework itself can use it means that it's not the issue. In fact the fact that large ... GIANT projects use it so heavily and work find with MANY MANY developers touching it points toward the issue being elsewhere on those teams you mentioned. Like i said most likely in a lack of documentation.
I can't find IRouteHandlerFilter, my project is .net 7, but getting The type or namespace name 'type/namespace' could not be found (are you missing a using directive or an assembly reference?)
It enables more functional programming, which is usually quite minimal (and correct) :-) Moving away from the rather clunky and OOP + convention based setup code is an improvement that will reduce time-to-production for a lot of APIs.
Awesome!!! 🤓 Questions: 1 - Do I even need MediatR when I have IRouteHandlerFilter and reflection working together? 2 - How can I create an endpoint with the validations for each Commands/Queries, so I can use as schemas to generate forms in any frontend framework? (Why this is not a thing I don't know... I guess everyone replicate their validations if not using a C# compatible language like blazor ou MAUI)
I feel in order to skip every single simple Controller I have to add a lot of extra codes/files in order to achieve the same thing. What's the point of using Minimal API now? Am I missing something?
One thing I don't like here, is that you specify the validation filter in a different place, to the expected parameters of the endpoint. If at any point the input model of the endpoint changes, you will only know about it in runtime. It's probably solvable with some custom Roslyn analyzers, or API automatic tests tho, but I'd still love things like validation filters being setup on the endpoint method, where you have fuller context. Maybe an attribute and assembly scan adding filters at the API startup?
You won't only know during runtime. I would expect people to have unit or integration tests around this. It would be very bad if you didn't have them, even if it was a generic constraint driven by the request type.
Hi, it seems [FromForm] is not available to use in minimal APIs. I needed to post an object with files (.text/.pdf) from a frontend (React) application to a .NET core 6 minimal API which does not seem to be possible using minimal API. Only because of that I might need to move back to the controllers which is really a pity. Do you see a workaround?
Someone will invent a architecture template that puts the entire app business logic using just filters and we’re all going to be made to use it by our architects
This is great. You never posted a followup to the FastEndpoints OS project video you did a few weeks back (you said in that video that you were going to do a followup). We are trying to determine if we want to go with pure Minimal APIs or try Fast Endpoints for our next production API. We're curious to know your further thoughts.
I would use controllers because of features but if i had special case where i wanted those 2-3k extra RPMs, i would go minimal. If adding more instances was not an option.
Another way Minimal API's comes closer to having certain features of Mediatr (in this case this looks a lot like mediatr pipelines). Nice vid; very interesting!
So is there a fancy way of doing this in "normal" controllers?. I am aware of Attributes and the Middleware approach but those seem a bit more "hacky".
Hi Nick. I have a new project to develop and planning to use minimal API's approach after following your recent videos. Would you recomend to use FastEndpoints library or do you think its better to organize endpoints on your own? Thank you for sharing such great content!
Looking at your code here, how is this simpler than current controllers? Looks to be just as much code, if not more, with the fact that you have that "MapCustomersEndPoints" method, and then still have to actually create the actions just like before. What am I missing here?
Controllers are a flawed/bad construct to use for APIs to begin with. They make sense architecturly and the only reason why we use them was because they just happened to have been there in MVC. Now for the video, that’s just one of the structures. My personal favourite way to structure an api with minimal api technology is this: github.com/Elfocrash/clean-minimal-api
So, if you ever need to expose the customer service over a different protocol or even simply expose it via a CLI, you would have to either write the exact same validation per framework, or inject it before the service. I wonder why not build it in the service itself. Said in another way, why would you allow your service to save an invalid customer?
There is yeah. From 5-25% depending on how efficient your IO calls are. If you have a database call that takes 100ms, then you won’t see the difference since the db call will “cover” it
With controllers, you can attribute with ApiController and it will automatically run validations and return error responses if there is a validation failure. you can use the fluentvalidations.mvc (I think it is) nuget package to plug into this without writing the filter yourself.
@@pilotboba Yeah but do you know how much stuff you are actually adding behind the scenes because of that ApiController attribute? You don't just get the validation. You also have no control over how that's implemented. If you want to optimize or customize anything you are extremely limited
@@nickchapsas sure.. You are required to use attribute routing. You get automatic 400 responses You get binding source parameter inference. Multipart/form-data request inference for FromForm attributes. You can also customize it with ApiBehaviorOptions. It's not very heavy and pretty much what you want most of the time. And it is opt in. You should always know what the magic gives you.
This is great. I have a question. In my apps i use controllers with mediator. With minimal api does it make sence to use mediator ? Or is it better to separete apis to more files to avoid boilerplate that comes with mediator?
Thank you Nick for all the great content. I getting the idea of the difference between MVC and minimal API, and understand that the minimal API is lighter. Still I more like the MVP approach with functions and property decoration instead of declaring evrything in the code itself Is more automated for my opinion The question is can it be done with the new approach? Or that this way is not recomended anymore?
The purpose of Minimal API is to be minimal. All the help and automation you get in a MVC project is what causes the poor performance. If you start introducing those helpers into a mininal api, then you might aswell just use MVC.
I know there are a lot of REST API's still out there and I think the recent changes to make API building more modular in C# is great. Moving away from the dated Controller architecture is really nice to see. I wonder if they're sort of still playing last years game though. REST API's are becoming more and more antiquated for me as most of the companies I and others work for are heavily investing in GraphQL API's now. In this GraphQL world, REST is nearly non-existent and used for hardly anything more than defining the `api/graphql` endpoint on a server. I hear folks saying to "check the future roadmap for minimal APIs." Is there something down that road which will compete with the strongly typed API schema, type handling, validation, auth flow management, etc that GraphQL offers?
Honestly, I think you're missing the point or misunderstanding the role of GraphQL. GQL is a way to aggregate various backend API's for various frontends - think Desktop (browsers) show different data to a mobile phone version (think: UI screensizes can determine what to show, etc). A GQL still needs to -source- the data from somewhere and that's where backend API's come in handy. Especially if the API's are various microservices.
@@JustinAdler That's not how we and many of my clients have our GraphQL API's built. It's also not what Apollo, "the Guild" of GraphQL, or the GraphQL open source project maintainers recommend. We do not do the "sourcing" that you're referring to as it's inefficient performance wise compared to implementing native GraphQL resolvers. GraphQL is very much a replacement to REST API's. The sourcing you're talking about is GraphQL Federation to stitch multiple API's together. I agree that this is a thing that is done, but on greenfield projects we and many others I know forego the entire REST -> GraphQL layer in favour of just straight up implementing the resolvers directly interfaced to the GraphQL schema without any REST data endpoints at all. Further on the topic of stitching, federation, and providing an API for multiple front-ends, it works better if the resolver types are directly interfaced into the GraphQL schema because it removes the mapping layer from your REST API to the types the resolvers provide. Also, by using the resolvers instead of a REST -> resolver mapping, you gain inherent bonuses for caching via DataLoader's and hierarchical resolution of data with incredible flexibility to retrieve only exactly what you ask for.
@@funknick seems like a big learning curve for GraphQL though. RESTApi, especially this minimal approach much easier to understand... for me anyway!! Plus I inherently want to stay away from anything related to Facebook!! :)
@@AthelstanEngland you are absolutely correct. It is a decently sized learning curve. I came from REST based web apps and had to jump into GraphQL for my current job. It took me a year to really get comfortable with the API pattern. I only push GraphQL because every company I know seems to be implementing with it or migrating to it (for better or worse). Ignoring industry trends is a good way to pass up relatively easy money. Who doesn't want easy money? For many projects, GraphQL is definitely overkill. Ultimately, it's not even necessary. GraphQL is to REST what React is to Angular. The reality is, no one really needed a replacement for REST or Angular, it already worked fine... but this is web dev, where we love to reinvent the wheel and call it a "revolution" every decade. *shrug* I get paid to do GraphQL, so I do GraphQL. Even if I'd prefer to just stick to my tried and true patterns and tools, I'm repeatedly forced to learn new things because someone saw a "shiny" and chased after it. There's no use fighting the tide, surf it and make the money. Fighting it will just tire you out and make life more difficult. Thankfully, in the case of GraphQL, the "shiny" isn't a random bawble, it's a decently cut gemstone.
By the way your invalid email is actually a valid email address :). SMTP did send directly to a host only in its first iterations, as that's how arpanet operated. The mailbox portion was added later, and the most recent version of the spec still allows for hostname-only addresses. The only correct way to validate an email address is to try and send an email to it.
Tell that to amazon, who still not allow any email with a TLD from after 2014 to be added as partner email. A bug I try to report every 6 months. Email validation is an artform with many distinct tastes.
While I like minimal APIs I don't like some of the missing features. In Controller based approach you only register Fluent Validators from an assembly and without adding a single line of code you have a fully working validation at Controller level. And in the new .NET 7 you need to have at least a custom filter. That sucks
You do add code in the startup to wire the validators and override the built in validation. You can get a similar thing with FastEndpoints which just need a validated to exist to register. Here is an example github.com/Elfocrash/clean-minimal-api
The difference is that you choose to opt in to the features you need on certain scenarios. It doesn't matter if eventually they have the same capabilities as Controllers. That was never the problem they are solving anyway. What matters is that the ground zero stays completely stripped off of everything,
@@nickchapsas don't get me wrong :) I started from owin pipelines so it was obvious feature for me. Just funny how different framework transforms to generally used patterns. Waiting for another silver bullet framework based on this )
So you mean you couldn't do it before .NET 7? What was missing? I thought custom middleware was there since .NET Core 1. Probably it's more complicated because of different routing mechanizm.
@@nickchapsas Right, the main different is the context. Access to arguments before the method is called and the ability to change the result before returning.
The default EmailAddress validator (so-called asp-net compatible) only checks that email address has '@' sign in it, and it is not first or last character. The regex check is implemented as alternative check mode, but is marked obsolete for some reason and not recommended.
@@OlegKosmakov Because the RFC for a valid email address is insanely complicated. Also not all email providers/services/software supports what is otherwise valid. The best way to go is to use the simple contains an @ sign, and send an email verification email with a URL validate link token thing. :)
Nick, what do you think about the necessity to handle 404 error separately from othe validation logic? I would love to be able to move this part from controllers/endpoints to validators but keeping the ability to return the NotFound response when an entity does not exist. Unfortunately, FluentValidation does not provide a way to do so. That is why I wrote my own extension for this: Pankraty.FluentValidation.HttpExtensions. Please, check this out, I think, you may find this approach very clean and convenient.
I don't like that type of response logic contained in my validator. My API-level validators should have one job. To tell me if the request coming in is valid or not. The 404 when a resource is not found is driven by my handler logic because it is a REST concern. I don't like handing that responsibility to FV
7:05 you could also do `OfType().SingleOrDefault()`
Yes, but `SingleOrDefault` is more efficient without `OfType` , because OfType will try to cast all elements of sequence and return some IEnumerable object, and then you use only single element from this IEnumerable.
Results of the simple benchmark with object[3] where only last element is of type:
| Method | Mean | Error | StdDev | Gen 0 | Allocated |
| OfTypeSingle | 124.15 ns | 2.422 ns | 2.790 ns | 0.0105 | 88 B |
| SingleByType | 44.38 ns | 0.920 ns | 0.860 ns | 0.0038 | 32 B |
@@alexanders_trail That's strange; I would hope it worked more lazily, nice insight
@@AlFasGD for SingleOrDefault() it requires at least 2 matches, whereas FirstOrDefault() needs 1 match, so you would expect a better perfomance with OfType().FirstOrDefault()
@@nanvlad Nick used SingleOrDefault, that's why I used this here too
The problem is that FirstOrDefault is dangerous and SingleOrDefault is used intentionally. I want to throw if for some reason two object of the same type have snuck in there. This is a generic method which could be used everywhere so if some endpoint for some reason has two types of the same type I want this to be an exception. FirstOrDefault will hide the problem and cause a bug silently. It should be used VERY carefully.
Nice, this is cool. We've been running validation through a mediatr pipeline then handling the validation exception in middleware to return bad requests. It'll make more sense to short circuit all that overhead and move validation entirely to the API.
Yeah i like MediatR to only handle my domain level validation and have my api level validation on the contract itself as a filter so that's a perfect addition
@@nickchapsas can you please give an example of domain vs contract level validation. i want to understand the need for both, seems most validation will be domain level even simple email address could be considered domain level.
@@zubairahmed3877 For example whether a property is mandatory or not or whether an email looks like an email. That would be api contract validation. Domain validation would check things specific to our application's domain logic, for example if another person with that same email is allowed in the system or not.
@@nickchapsas Does your domain layer generally check the format of the email too? If yes, wouldn't this result in duplicate validation code? I generally never validate on api side as the domain already has rules about data format when creating Value Objects. Is that a bad approach?
@@benjaminb.4043 I go back and forth on email validation. Sometimes it’s in domain only sometimes it’s in both places but that’s a bit of a problem so I tend to only keep it on the domain
1:56 Happy birthday. It's five days too late, but I guess it still counts.
So, what we see, is that the webapi approaches are turning more to a functional style of programming. Mediatr is a kind of a wrapper of a function, now these minimal apis and filters, we just combine functions together. Every release we have less OOP and more functional things. I hope some day we'll have an ability to use decriminated unions in C# and this will allow to perfectly describe business logic of the app.
It makes sense since even on the C# level they are getting heavily inspired by F# features and functional concepts in general
I think there's `OfType` LINQ extension method so that you don't have to do that `x = > x.GetType() == typeof(T)`
OfType will try to cast every type. The expression will only check it
@@nickchapsas It will only cast types that passes an "is" test, which would be more flexible than exact type matching.
That’s quite a good point.
x => x is T would be slower?
@@rogeriobarretto It would be slower, but probably not in any significant way.
That's super cool, I am waiting for this for a while now for MinimalAPI 👏
The name has been changed to IEndpointFilter now.
Happy B-Day man!
I don't find the "AddFilter" Method and the IRouteHandlerFilter Interface. My dotnet --version is 7.0.100. (Downloaded today). Any idea?
I have the same problem and almost exact the same SDK version (7.0.101). Does anyone know the answer? I use Rider IDE.
@edit:
Okay I have the answer. It has been renamed to "IEndpointFilter" interface. Similarly, "AddRouteHandlerFilter" method has been replaced with "AddEndpointFilter" etc.
IRouteHandlerFilter is renamed to IEndpointFilter, and AddFilter is renamed to AddEndpointFilter.
Fantastic filter validators ! ☀️🕺🌲
I would like to see your view on IDisposable, best practices and when to use it where people might forget it. Love your videos 👌
I'm not sure there's much room to look at IDisposable - You want to use it to clean-up unmanaged resources explicitly. Sure, you could wait for the GC to get around to cleaning up the object to call the destructor/finalizer that has your code to clean it up implicitly, but you have no idea when thats going to happen. IDisposable lets you clean up the unmanaged resources immediately leaving only the wrapper on the managed side that the GC has to clean up. (You can disable finalization calls on a Dispose call so the GC won't try to repeat it) You can also use a Using statement to call Dispose implicitly at the end of the scope which is handy for filestreams.
Only other instance I have seen for this is relating to events. If a class for example is subscribed to a publisher/event then it will be kept alive/won't be collected until it unsubscribes or until the publisher is cleaned up. Publishers keep subscribers alive, but subscribers don't keep publishers alive. Some people opt for a weak pattern to prevent this.
Another great video Nick!
Hi, do you have the repo updated with filters in .net 7 with minimal APIs?
This is really cool, I'm glad that's a possibility in 7. So the reason why this is not possible earlier, is it because the AddFilter method isn't defined?
Now that Parameters property has been renamed to Arguments.
A big benefit of filters in MVC is that you can apply them per-controller or per-project. Do you know if that's available (yet) with this approach, or do you literally have to go and add `.Filter()` to every endpoint to do fully cross-cutting concerns (like model validation for instance)?
i have never worked with minimal apis so i dont know if there is a framwork way to do project level filters, but a c# way that comes to mind would be to just write an extension method on the webapplication, so you basically have your own mappost where you already add the filters if you know what i mean
You can apply filters per endpoint or per project. That’s exactly what I showcase in the video
@@nickchapsas yeah the per endpoint are clear but i couldnt find a per project one in this video. maybe im misunderstanding something but all filters shown in the video look like enpoint scoped to me
@@nickchapsas Sorry I must have missed the per-project one.
@@nickchapsas I might be missing something but I'm only seeing AddFilter method used on MapGet, MapPost etc in the video, meaning I would need to call that for all endpoints using the filter. Is there no way to add a generic validation filter for all endpoints? If not that is still a good use case for MediatR since it is possible to do that there.
Swagger documentation capabilities were also a gap last I checked… I think all the other major boxes are checked after that?
Swagger documentation was supported but they are expanding on it even further in .NET 7. Which feature were you missing?
Filters seem nice. I think pulling the validations from the assembly using reflection is evil voodoo and should be avoided. A clearer pattern would be too map the model validator to the validator filter directly like ValidationFilter where T : IValidator (or whatever the validator interface is) so you could call .AddFilter()
I don't agree that assembly scanning is bad. It is extremely common and the .NET platform is using it extensively behind the scenes and it's something that almost all libraries, like MediatR, AutoMapper, FluentValidation etc have adopted.
@@nickchapsas I know what you mean. I used to write a lot of code like that because it's more convenient and less typing. I've found over the years though that it ends up causing more headaches than it's worth.
When it's in the .net framework and the usage is well documented and replicated and explained in tons of tutorials/codebases it's a little bit different.
If you're writing code like that in a team, you're essentially adding magic behaviour and it causes issues and confusion.
As an example, being able to right click and Find All Usages of a class/interface/method (or a text search) to see where it's being used is invaluable when debugging or refactoring.
I can't tell you how often this pattern has burnt all of the different teams I've worked on, but I can say every time it gets implemented it ends up being way more inconvenient in the long run by far.
Technical debt at its finest 💸.
@@kelton5020 IT sounds more like poor documentation and commenting is more your issue than magic behaviour. The fact that most large projects and the framework itself can use it means that it's not the issue. In fact the fact that large ... GIANT projects use it so heavily and work find with MANY MANY developers touching it points toward the issue being elsewhere on those teams you mentioned. Like i said most likely in a lack of documentation.
I can't find IRouteHandlerFilter, my project is .net 7, but getting The type or namespace name 'type/namespace' could not be found (are you missing a using directive or an assembly reference?)
Can we just register validators from the assembly in Startup, and trigger them automatically before stepping into the endpoint?
Yes you can, been doing it for years now (using fluentvalidation)
Combining FluentValidation with controllers, yes, but with minimal apis the recommended approach (for .net6 anyway) is to use IValidator directly.
Making "Minimal API" complex enough, one step a time, until it is not minimal anymore.
Minimal API is about choice of structure and simplicity of building blocks. Not about having everything in a single class.
My thoughts exactly!
In .NET 10 it will be renamed to Maximal API
It enables more functional programming, which is usually quite minimal (and correct) :-) Moving away from the rather clunky and OOP + convention based setup code is an improvement that will reduce time-to-production for a lot of APIs.
Totally agree with this - this isn’t where I was hoping the API would go. I’m just relieved it’s not attribute based at least!
Why IRouteHandlerFilter interface not found .net 7
Awesome!!! 🤓
Questions:
1 - Do I even need MediatR when I have IRouteHandlerFilter and reflection working together?
2 - How can I create an endpoint with the validations for each Commands/Queries, so I can use as schemas to generate forms in any frontend framework? (Why this is not a thing I don't know... I guess everyone replicate their validations if not using a C# compatible language like blazor ou MAUI)
1. in my opinion, no
2. I didn’t understand this one
Is there any performance test if minimal api run faster than api controller? It looks like a lot of work to organize the minimal api.
0:53 wait do you mean you use it professionally in production or only on your own projects?
Both
How would you tie this in with the minimalist mediatr you demo'd
I feel in order to skip every single simple Controller I have to add a lot of extra codes/files in order to achieve the same thing.
What's the point of using Minimal API now? Am I missing something?
One thing I don't like here, is that you specify the validation filter in a different place, to the expected parameters of the endpoint. If at any point the input model of the endpoint changes, you will only know about it in runtime.
It's probably solvable with some custom Roslyn analyzers, or API automatic tests tho, but I'd still love things like validation filters being setup on the endpoint method, where you have fuller context.
Maybe an attribute and assembly scan adding filters at the API startup?
You won't only know during runtime. I would expect people to have unit or integration tests around this. It would be very bad if you didn't have them, even if it was a generic constraint driven by the request type.
Happy birthday!
could you even go further and use source generator to create the specific customer type at compile time instead of reflection GetType ?
No because source generators can’t change existing code but the get type check is extremely fast and not a problem
Hi, it seems [FromForm] is not available to use in minimal APIs. I needed to post an object with files (.text/.pdf) from a frontend (React) application to a .NET core 6 minimal API which does not seem to be possible using minimal API. Only because of that I might need to move back to the controllers which is really a pity. Do you see a workaround?
Hi Nick, the coupon is not working anymore, any chance to get one?
“Oops! An error occurred!
Please refresh the browser” appears after a purchase course button on your website on iPhone.
@Nick can you make video about nullable and how does it affect performance
Someone will invent a architecture template that puts the entire app business logic using just filters and we’re all going to be made to use it by our architects
dont give ideas :)
This is great. You never posted a followup to the FastEndpoints OS project video you did a few weeks back (you said in that video that you were going to do a followup). We are trying to determine if we want to go with pure Minimal APIs or try Fast Endpoints for our next production API. We're curious to know your further thoughts.
I sent that video privately to the creator of FastEndpoints and he addressed all the issues. I didn’t want to put the library on a negative light.
When building a REST API in .NET, will you go with Minimal API or Controller-based?
I use Minimal APIs
i feel like controllers produce more readable code, but each to their own
I would use controllers because of features but if i had special case where i wanted those 2-3k extra RPMs, i would go minimal. If adding more instances was not an option.
Does the minimal Api Template has Swagger build in?
It does
Excellent thanks.
Another way Minimal API's comes closer to having certain features of Mediatr (in this case this looks a lot like mediatr pipelines). Nice vid; very interesting!
Filters and Middleware are old feature in .net core. You don't need to use mediatr or .net 7
Is there a way to setup a filter to all the endpoints at once without needing to be endpoint specific?
You can iterate over the endpoints and call the AddFilter method
@@nickchapsas how to iterate over all endpoints?
@@lolroflxd You can store the returned value of the registration in a list and then iterate the list
So in short, filters are middleware or uses the middleware pattern. Nice, we getting closer to express js
So is there a fancy way of doing this in "normal" controllers?. I am aware of Attributes and the Middleware approach but those seem a bit more "hacky".
Which IDE are you using here?
JetBrains Rider
FILTERS code is not working. Are talking about auth Tokens in the course ?
Yep, FILTERS code not working. I'll wait until it works. :)
Hi Nick. I have a new project to develop and planning to use minimal API's approach after following your recent videos. Would you recomend to use FastEndpoints library or do you think its better to organize endpoints on your own? Thank you for sharing such great content!
Totally. That’s what I do as well
So basically a middleware that you can scope to specific endpoints?
Effectively yes
Looking at your code here, how is this simpler than current controllers? Looks to be just as much code, if not more, with the fact that you have that "MapCustomersEndPoints" method, and then still have to actually create the actions just like before. What am I missing here?
Controllers are a flawed/bad construct to use for APIs to begin with. They make sense architecturly and the only reason why we use them was because they just happened to have been there in MVC. Now for the video, that’s just one of the structures. My personal favourite way to structure an api with minimal api technology is this: github.com/Elfocrash/clean-minimal-api
@@nickchapsas Thank you for for the reference. I'll have a look.
I remember Nick saying the min api's don't allow for properly isolates unit tests. Is that no longer true?
They are fixing that too in .NET 7
@@nickchapsas I would be interested in seeing more about this
@@jackkendall6420 I will be making a video on it
So, if you ever need to expose the customer service over a different protocol or even simply expose it via a CLI, you would have to either write the exact same validation per framework, or inject it before the service. I wonder why not build it in the service itself. Said in another way, why would you allow your service to save an invalid customer?
Are you updating the minimal api zero to hero course with a filters section by any chance?
When .NET 7 comes out I will
Great video again Nick. Just in case, there is any performance difference between "Classic API" using Controllers and Minimal API?
There is yeah. From 5-25% depending on how efficient your IO calls are. If you have a database call that takes 100ms, then you won’t see the difference since the db call will “cover” it
It feels like they slowly want to replace MVC (or create a competitor) with Pipeline RequestDelegates.
Which is great because you can build exactly what you need without the limitations from MVC
Hello, sorry i'm a bit new to web api, but it's look great features.
Is this applicable to MVC approach ?
This is only applicable to minimal APIs. MVC has a version of this already
With controllers, you can attribute with ApiController and it will automatically run validations and return error responses if there is a validation failure. you can use the fluentvalidations.mvc (I think it is) nuget package to plug into this without writing the filter yourself.
@@pilotboba Yeah but do you know how much stuff you are actually adding behind the scenes because of that ApiController attribute? You don't just get the validation. You also have no control over how that's implemented. If you want to optimize or customize anything you are extremely limited
@@nickchapsas
sure..
You are required to use attribute routing. You get automatic 400 responses
You get binding source parameter inference.
Multipart/form-data request inference for FromForm attributes.
You can also customize it with ApiBehaviorOptions.
It's not very heavy and pretty much what you want most of the time.
And it is opt in.
You should always know what the magic gives you.
This is great. I have a question. In my apps i use controllers with mediator. With minimal api does it make sence to use mediator ? Or is it better to separete apis to more files to avoid boilerplate that comes with mediator?
It doesn’t really make sense no. You can get an example of the structure here github.com/Elfocrash/clean-minimal-api
is the course not in the Bundle ?
It is not. Course bundles are logical grouping and that course doesn't belong in one yet
It works only in dotnet 7 preview?
For now yes
Super cool! Solves the problem of deserializing the request multiple times. Does this work for other content types as well, such as forms?
As long as they get mapped to the object then yeah
Thank you Nick for all the great content.
I getting the idea of the difference between MVC and minimal API, and understand that the minimal API is lighter. Still I more like the MVP approach with functions and property decoration instead of declaring evrything in the code itself
Is more automated for my opinion
The question is can it be done with the new approach? Or that this way is not recomended anymore?
The purpose of Minimal API is to be minimal. All the help and automation you get in a MVC project is what causes the poor performance. If you start introducing those helpers into a mininal api, then you might aswell just use MVC.
The issue is MinimalAPI is for... APIs MVC is for things that need ... Views... Hence mVc api's don't need views.
Nick has a video on structuring Min APIs for larger projects which may be worth watching, called in Defence of Minimal APIS or similar.
When to develope when new versions and features comes out every 2 days?!! :D
It gose foo foooo.. nice :):):)
I know there are a lot of REST API's still out there and I think the recent changes to make API building more modular in C# is great. Moving away from the dated Controller architecture is really nice to see.
I wonder if they're sort of still playing last years game though. REST API's are becoming more and more antiquated for me as most of the companies I and others work for are heavily investing in GraphQL API's now. In this GraphQL world, REST is nearly non-existent and used for hardly anything more than defining the `api/graphql` endpoint on a server.
I hear folks saying to "check the future roadmap for minimal APIs." Is there something down that road which will compete with the strongly typed API schema, type handling, validation, auth flow management, etc that GraphQL offers?
Honestly, I think you're missing the point or misunderstanding the role of GraphQL. GQL is a way to aggregate various backend API's for various frontends - think Desktop (browsers) show different data to a mobile phone version (think: UI screensizes can determine what to show, etc). A GQL still needs to -source- the data from somewhere and that's where backend API's come in handy. Especially if the API's are various microservices.
@@JustinAdler That's not how we and many of my clients have our GraphQL API's built. It's also not what Apollo, "the Guild" of GraphQL, or the GraphQL open source project maintainers recommend. We do not do the "sourcing" that you're referring to as it's inefficient performance wise compared to implementing native GraphQL resolvers. GraphQL is very much a replacement to REST API's.
The sourcing you're talking about is GraphQL Federation to stitch multiple API's together. I agree that this is a thing that is done, but on greenfield projects we and many others I know forego the entire REST -> GraphQL layer in favour of just straight up implementing the resolvers directly interfaced to the GraphQL schema without any REST data endpoints at all.
Further on the topic of stitching, federation, and providing an API for multiple front-ends, it works better if the resolver types are directly interfaced into the GraphQL schema because it removes the mapping layer from your REST API to the types the resolvers provide. Also, by using the resolvers instead of a REST -> resolver mapping, you gain inherent bonuses for caching via DataLoader's and hierarchical resolution of data with incredible flexibility to retrieve only exactly what you ask for.
@@funknick Agree
@@funknick seems like a big learning curve for GraphQL though. RESTApi, especially this minimal approach much easier to understand... for me anyway!! Plus I inherently want to stay away from anything related to Facebook!! :)
@@AthelstanEngland you are absolutely correct. It is a decently sized learning curve. I came from REST based web apps and had to jump into GraphQL for my current job. It took me a year to really get comfortable with the API pattern.
I only push GraphQL because every company I know seems to be implementing with it or migrating to it (for better or worse). Ignoring industry trends is a good way to pass up relatively easy money. Who doesn't want easy money?
For many projects, GraphQL is definitely overkill. Ultimately, it's not even necessary. GraphQL is to REST what React is to Angular.
The reality is, no one really needed a replacement for REST or Angular, it already worked fine... but this is web dev, where we love to reinvent the wheel and call it a "revolution" every decade. *shrug*
I get paid to do GraphQL, so I do GraphQL. Even if I'd prefer to just stick to my tried and true patterns and tools, I'm repeatedly forced to learn new things because someone saw a "shiny" and chased after it. There's no use fighting the tide, surf it and make the money. Fighting it will just tire you out and make life more difficult.
Thankfully, in the case of GraphQL, the "shiny" isn't a random bawble, it's a decently cut gemstone.
By the way your invalid email is actually a valid email address :). SMTP did send directly to a host only in its first iterations, as that's how arpanet operated. The mailbox portion was added later, and the most recent version of the spec still allows for hostname-only addresses. The only correct way to validate an email address is to try and send an email to it.
Tell that to amazon, who still not allow any email with a TLD from after 2014 to be added as partner email. A bug I try to report every 6 months. Email validation is an artform with many distinct tastes.
Looks like we wait for another 6 months , and Visual Studio will support all these features
While I like minimal APIs I don't like some of the missing features. In Controller based approach you only register Fluent Validators from an assembly and without adding a single line of code you have a fully working validation at Controller level. And in the new .NET 7 you need to have at least a custom filter. That sucks
You do add code in the startup to wire the validators and override the built in validation. You can get a similar thing with FastEndpoints which just need a validated to exist to register. Here is an example github.com/Elfocrash/clean-minimal-api
Basically middleware, awesome!
Hello Nick, it would be great if you can provide code repo so we can try it easily.
Thanks!
The code in my videos is available to my Patreons
:) in several iterations it will be same mvc pipeline) or mediatr behaviour.
The difference is that you choose to opt in to the features you need on certain scenarios. It doesn't matter if eventually they have the same capabilities as Controllers. That was never the problem they are solving anyway. What matters is that the ground zero stays completely stripped off of everything,
@@nickchapsas 100% accurate
@@nickchapsas don't get me wrong :) I started from owin pipelines so it was obvious feature for me. Just funny how different framework transforms to generally used patterns. Waiting for another silver bullet framework based on this )
The MinimalAPI just got a bit more powerful :)
So you mean you couldn't do it before .NET 7? What was missing? I thought custom middleware was there since .NET Core 1. Probably it's more complicated because of different routing mechanizm.
Correct, you couldn't. In Minimal APIs you could not have filters or action specific middleware. Now, in .NET 7, you can.
@@nickchapsas Right, the main different is the context. Access to arguments before the method is called and the ability to change the result before returning.
I was coding along only to realise later that I'm on .Net 6. Silly me.
Honestly i don't like it because the execution order isn't from up to down....
You born 4/20? I was
why dont use .EmailAddress() as validator instead of regexp? :)
Very good point. My brain completely forgot about that
The default EmailAddress validator (so-called asp-net compatible) only checks that email address has '@' sign in it, and it is not first or last character. The regex check is implemented as alternative check mode, but is marked obsolete for some reason and not recommended.
@@OlegKosmakov I have to look deeper into this then because I remember someone using regex instead of the EmailAddress one at work
@@OlegKosmakov Because the RFC for a valid email address is insanely complicated. Also not all email providers/services/software supports what is otherwise valid.
The best way to go is to use the simple contains an @ sign, and send an email verification email with a URL validate link token thing. :)
Nick, what do you think about the necessity to handle 404 error separately from othe validation logic? I would love to be able to move this part from controllers/endpoints to validators but keeping the ability to return the NotFound response when an entity does not exist. Unfortunately, FluentValidation does not provide a way to do so. That is why I wrote my own extension for this: Pankraty.FluentValidation.HttpExtensions. Please, check this out, I think, you may find this approach very clean and convenient.
I don't like that type of response logic contained in my validator. My API-level validators should have one job. To tell me if the request coming in is valid or not. The 404 when a resource is not found is driven by my handler logic because it is a REST concern. I don't like handing that responsibility to FV