Fix Your Controllers By Refactoring To Minimal APIs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I'm about to teach you how to convert your controllers into minimal apis for a better design more cohesion and improved performance so let's dive in controllers have been around since the early days of building apis in.net and to create one you need to implement one of the controller base classes in this case I'm implementing an API controller so I'm implementing the controller base base class and I'm also decorating it with the API controller attribute to define a route for your controller you use the route attribute and then every method that you define inside of the controller class becomes an endpoint but you also have to decorate the method with the respective HTTP attribute so in this case I'm defining a post endpoint and a get endpoint and so on so what is the problem with controllers all of the methods inside of a controller class represent specific separate endpoints which means they have pretty much nothing in common and Azure controller grows it becomes harder to maintain because the cohesion between the endpoints is pretty low also all of the controller endpoints share the same dependencies in this case my controller is very thin because I only have one service but if you have multiple Services they will be shared between all of your endpoints and realistically you only need one or two services for a single endpoint which means that you are wasting memory and allocating more resources than you need to satisfy the Constructor of the controller regardless of if the endpoint that is being invoked will use all of the services or not so let's convert the products controller into minimal apis and see what are the differences between the two I'm going to make a copy of this class and I'm going to be adding the minimal API endpoints inside of the copy so let's call this class products endpoint and I'm going to rename the file to match the name of the class because I'm going to be defining minimal apis I can completely get rid of the attributes that were decorating this class and also get thread of the controller base base class I'm not going to be needing the Constructor injecting the eye sander because minimal apis use a different approach for dependency injection and let's try to fix all of our endpoints to use minimal apis and then I'm going to show you some other features of minimal apis first of all we need access to one of the interfaces that allows us to define a minimal API endpoint and one of those is the eye endpoint route Builder so what I can do is make this class static and Define a static method inside which I will call map product endpoints I'm going to Define an extension method on the I endpoint route Builder and we're going to use this instance to Define our minimal API endpoints so to define a post endpoint you would say map post the same applies if you want to map to the other HTTP verbs so you would have map get map data delete map put and so on so first of all I need to define a route for my endpoint and this one is API slash products this is going to match the create product endpoint that we had in the controller then I need to define a body for my request and this is going to include two things first of all I need to pass in any data that I want to have inside of my minimal API endpoint and secondly I also need to inject any service that I may need to satisfy my request so in this case I'm going to inject the I sender from mediator and this is how you use dependency injection with minimal apis so minimal apis uses method injection whereas with controllers you would typically use Constructor injection I'm also noting that controllers do support method injection so you could be using this approach regardless but this is how you do it with minimal apis then I'm going to take the contents of this method and move it into my minimum API endpoint I'll fix the sender and what are we going to do with the OK method this method was exposed by the controller base class but with minimal apis you have access to the results class which is a factory for creating various types of results and you can just say results.okay and you will see that all of the methods have the same names as with controllers so with this in place our minimal API endpoint is functional but I also want to show you an alternative approach to how you can configure this endpoint and we're actually going to reuse the existing method that we have from our controller so here's what I'm going to do I'm going to move the parameters into individual lines and I'm also going to inject the I sender so this will be the create product endpoint let's fix the contents inside so this is going to be a task and it's going to return an eye result which is going to match what the minimal API endpoint is expecting then I can say return result dot ok I'm going to get rid of the HTTP post attribute and I'm going to make this method static this is important for two reasons first of all I'm inside of a static class and I can't have instance methods and secondly now I can take the create product method and pass it as the request Delegate for my minimal API endpoint you can see how this simplifies the minimal API definition and there's another benefit to this because the create product method is now public on our static class which means that we can use it inside of our tests so if you want to unit test your minimal API endpoints It's relatively easy to do I'm just going to show you a quick example so I'm not going to be writing the entire test but what you would do is say product endpoints and then you have access to the create product method and you can call it and test the result that you get back now I personally only think that unit testing your controllers is completely pointless because they don't really contain any behavior all they do is just pass the request along to the other services it's far better to use functional testing where you actually call your API using an HTTP client instead of unit testing the individual methods so let's also convert the other endpoints that we have to minimal apis I'm going to make this static and I need access to the I sender from mediator then I'm going to fix sending of my query and let's return results dot OK I also need to update the return type to be an eye result now I can go ahead and say app map get and this is going to be the API slash products endpoints and we can say get products and this is how easy it is to move from controllers into minimal apis this endpoint is slightly different because we're giving an name to a route and I'm going to show you how to do this with minimal apis so let's start by getting rid of this attribute then I'm going to make this static we're going to update the return type to be eye result and we're also going to inject the I sender from mediator now I can send my query return an OK result if everything succeeds or I can return a not found result if I run into an exception let's also do this for the remaining endpoints that we have so I'm going to make this static let's move the arguments into separate lines we need to make this into an eye result I need to add the I sender from mediator and then I need to fix my endpoint body this is returning no content in a success path and the not found result in case of an exception and let's also fix the delete endpoint I'm going to make it static return I result from this method give it the eye sender using method injection and let's just fix the compile errors so now that we have all of our static methods we can go ahead and easily Define our endpoints so I'm going to say map get the route is API slash products slash ID and we can say get product so single not plural then I'm going to map the put endpoint the route is going to be the same as with our get product endpoint so update product and we also have a delete endpoint for deleting a product with the same route and we can pass it the delete product method all right and we just defined all of our minimal API endpoints instead of using controllers remember that these endpoints also had a name associated so how you can do that with minimal apis is by saying with name and then you can pass in what is the name of this endpoint so this is the get product I'm going to use the name of operator for compile time safety this one will be update product and this one will be delete product now we are functionally equivalent with our controller however you can see that the route for individual endpoint is present repetitive and with a controller we had a route on the controller level which would Define the base path of the route and then we would have the remainder of the route and the individual endpoints so how you can do this with minimal apis is by calling map group and this will allow you to map an endpoint group you need to specify what is the prefix for the API route for this group so I'm going to say API products and I'm going to take the group Builder into a variable then I can map the individual endpoints using this route group Builder and I need to get rid of the repetitive part of the route so I'm going to delete API products from all of the routes and this is what I am left with so the cool part about using proud groups is that now you can further decorate your group for example you can add rate limiting with the required rate limiting method and specify some rate limit policy you can also Define authentication by calling require authorization you can also specify what is the authorization policy that applies to all of these endpoints but I'm not going to be using any of that right now so right now we have a set of minimal API endpoints that are functional equivalent with our controller but they are not part of the public API because we didn't call the map product endpoints method so you would call that from the program class and you can say here instead of mapping your controllers you can say map product endpoints and you will define an extension method for each of your minimal API endpoints and this is the slight downside to this approach because you have to remember to call this method every time that you define a minimal API endpoint so there's a library that allows you to do this automatically and it's called Carter so this is an alternative to defining your minimal apis and I'm going to show you how you can use it so you'll install the Carter Library then you need to configure the required services so you say Builder services at Carter then I need to map The Carter endpoints so I'll say app map further this is going to scan my assembly and look for any implementations of the iqarter module interface then it's going to call the respective method inside to register the endpoints so here's what that will look like so now our class is no longer static because it needs to implement the icarder module interface this interface exposes one method which is the add routes method and I'm going to put it at the top of this class and inside of it we're going to Define our individual endpoints this is as easy as just copying all of this code and adding it here so now we are defining our endpoints using Carter instead of using static methods which also means that I can get rid of this call here and now when I call map Carter it's going to instantiate this Carter module and call the add routes method to Define my minimal API endpoints so these are the two common ways how you can register your endpoints with the runtime and I want to talk about one more point about minimal apis and that is strong typing so right now we've been using the I result interface to represent the results of our minimal API endpoints but this approach isn't strongly typed and it's also missing some important metadata that is required for generating your API contract and with Net 7 there's an option to use strongly typed results with minimal apis and I'm going to show you how to do that so instead of using the results class to generate your responses you would be using the tight results I'm going to find an endpoint with more than one return type such as this one that returns an OK and a not found result and I'm going to show you how to use strongly typed results so let's start by using a typed results here you'll see that this class exposes the same set of methods as the results class however the return type is different so if we check out what results that not founder is returning it's the I result interface and typed results not found returns are not found result so in this case it's also strongly typed to our argument which is a string and in the case of the type results okay this is going to be the product response we are still returning the I result interface from our method and how we will turn this into a strongly typed result is by saying results and you can use the generic variant and then you can Define the individual results returned by this method so you can say OK of product response this is going to match the first return type and I'm going to say that this also returns a not-found response and this one is of type string which is going to match our second return type so you can see that this is much more verbose than using the I result interface but it's also strongly typed and is going to help Swagger better understand what your minimal API endpoint is returning and in turn is going to generate a better API contract I hope this video was valuable and that you learned something new about minimal apis don't forget to smash that like button on your way out and until next time stay awesome
Info
Channel: Milan Jovanović
Views: 35,428
Rating: undefined out of 5
Keywords: minimal apis, minimal apis c#, minimal apis vs controllers, minimal apis dependency injection, minimal apis dotnet, minimal apis authentication, minimal apis swagger, minimal apis in asp.net core 6, minimal apis middleware, asp.net minimal apis, minimal apis controllers, controllers to minimal apis, refactor controllers to minimal apis, minimal apis .net 6, minimal apis .net 7, minimal apis .net 8, minimal apis clean architecture, minimal apis vertical slice architecture
Id: gsAuFIhXz3g
Channel Id: undefined
Length: 14min 55sec (895 seconds)
Published: Fri Sep 08 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.