In defence of .NET Minimal APIs | Refactoring

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody i'm nick in this video i want to address a lot of the criticism that minimal apis are getting in dotnet 6 mainly because i did make a video on the feature showcasing it and you can see the code i came up with here it's very simple this is all the code we have for the api and even though the video did great and it got very good feedback on the feature itself the feature also got a fair amount of criticism people are saying that this is just for demos that this would never scale you would never put this in production this is just to come up with something and throw it away or that this is not like my enterprise application whatever that means so in this video i want to basically debunk all this i'm going to refactor this to a more elegant way of using minimal apis and it will be something that i would personally put to production i'm also going to run load tests against that and the equivalent of this in the old mvc or web api approach and show you how you can make this testable and why minimal apis are overall a great feature that i will be using if you like the content and you want to see more make sure you subscribe in the certification bell to get related when i upload a new video so i haven't really changed anything from that first video the only thing i've done is i've added this secret source folder here i won't show you what's in there but we will be using the secret sauce to make this a more elegant api and as i'm going along i'm going to show you what's in there so let's clean this up a bit because currently two things shouldn't be here this customer record and this customer repository those should not be here so let's clear it up i'm going to go ahead and make a new folder here and i'm going to call this models and i'm going to make another one and i'm going to call it repositories and the first thing i want to do is i want to create a new class here so i'm going to create the customer class so customer.cs and i'm going to copy that record and put that in there here is a record with the namespace all nice and tidy and i'm going to do the same for the customer repository so i'm going to create a new custom repository here and then i'm going to paste the code exactly as it is so the code is here let me just import all the missing stuff which should be just the customer model great so that's here so the two things that shouldn't be there in the first place are no longer there now the next thing that could be better is actually these endpoints because if you just keep adding in points using the map method in the program.cs this will get very bloated also this is not really uni-testable at this stage so how do we do that well let's fix the bloating thing first so what i'm going to do is i'm going to create a new folder and i'm going to call that endpoint definitions and what i'm going to do is since i want to define a bunch of endpoints in a structured way i'm going to call this the customer endpoint definition and this is where i'm going to define my endpoints so this will implement the i endpoint definition interface and i'm going to import that and then i'm going to implement the members and it has two methods it has a define endpoint method and it has a defined services method you probably understand where this is going in the services i'm going to register all the di components that i need for those endpoints and in the define endpoints i'm going to define my endpoints so the first thing i want to do is i'm going to take all of these endpoints here just cut them and paste them in here and then i'm going to import all the missing things like the customer repository and the customer model so that is now here and then the other thing i was registering up here is the customer repository so it will no longer be here so i'm going to delete that and i can delete that as well and i'm going to register it where it should be in that define services method so services.add singleton like it was and then customer repository goes here and now i have my custom repository registered and really that's it in terms of organization i'm going to show you how we can turn this into something that is unique testable but for now that's all the restructuring we're going to do but obviously now we no longer actually register those endpoints in the middlewares and the dependency injection framework so how do we fix that well i'm going to go in the builder here i'm going to say builder.services.add endpoint definitions and this is one of the methods in the secret sauce folder and what i want to do in this method because it accepts an array of types i will need to give it a pointer to assembly scan my assembly to find everything implementing this interface and register all those endpoints dynamically so all i want to do is say type of and then point to any of the types that i can see in this project i can use the customer one it doesn't matter any type would do this has nothing to do with what we're actually registering this has everything to do with the assembly scanning so that's done now and the last thing i want to do is say app.use endpoint definitions another secret source method and now that's it that's your program.cs that's your endpoint definition very organized you can see what services are required for this specific um endpoint definition and you can work with it and if you want to add more you can add it here and if you want to add more endpoints you can add them here and now all i'm going to do is i'm going to just run this to show you that it actually still works so api is running i'm going to try to get all the customers i have nothing in the database the in-memory database so i'm going to go ahead and create one and as you can see nick was created i can now list it this is all calling that api by the way and in case you don't believe me for some reason um i can put a breakpoint here and then hit that endpoint and you see that this endpoint is hit this is exactly where my code is going and now i can go ahead and if i want now read it i can read it i can update it to my evil brother tom trapses which doesn't exist and then i can delete that and as you can see nothing in the database anymore and this is significantly more organized but the problem is is this really flexible so let's see this thing doesn't currently have swagger so how do we enable swagger support well it's actually pretty easy all i want to do is i want to create a new endpoint definition so i can say swagger endpoint definition here and you don't have to do this you can make an extension method specific to swagger and do that um in the program.cs but i don't want to bloat this program.cs so i'm going to do it this way so i'm going to say i endpoint definition like i did before i'm going import that i'm gonna implement the missing members and then i need to implement these two methods for swagger middlewares you need these two use swagger and use swagger ui and for the services you need these two the add endpoints api explorer and the add swagger gen and once i do that that's the only thing i added by the way i didn't touch anything else in the whole project i'm gonna run this and then i'm gonna go to my web browser and as you can see simple api swagger support i can go in the endpoints i can call them and they return obviously nothing now because nothing is in the database i can do all of those things and i didn't have to change anything in my project and i now have swagger support dynamically so that's i think a really cool and nice way to go about it now let's go ahead and make this a bit more proper because the problem with this approach is that now i can't really unit test this you know how do you write a unit test that has some mock data in the customer repository and then you assert against that you cannot so the way you can do it is i'm going to create obviously an interface and you can create an interface in a separate file but for the purposes of this video i don't really need to and sometimes i just keep both interface and class in the same file for brevity so i'm just gonna add every endpoint so let me just quickly cut here so every method is now added in the interface and what i want to do is say i customer repository and once i have that i can go back to the thing that concerns this repository which is the customer endpoint definition and all i need to change is say i customer repository to custom repository oh and of course i have to update the usages of the um customer repository so this goes here this goes here and this goes here and now if i run this this should still be working and it is i can go ahead create customer as you can see and swagger is still working as well so now this is an interface doesn't necessarily mean that it's testable so how do you test this delegate well it's actually very simple you can just extract it so what is this this is a method really that accepts um a repository and a customer repository and a good and it returns an eye result so let's take a look at what this looks like this is a get customer by id so what i'm going to this i'm going to say internal i result because that's what that thing is returning and then i'm going to call this get customer by id you can omit the customer because it's a bit of a redundant thing within the context of this um class but you can leave it there if you want and then put the i customer repository and the grid which is what this method is expecting and then i can just take that code out of here and put it here and now this method since all this really was was a delegate is i can remove that and i can do this and now this is perfectly acceptable code you can go ahead and do it with every other of the methods and since this is an internal thing you can now perfectly find unit tested you can inject the i customer repository and the grid that you want and you can assert against the result exactly like you would do on any other project really now you can even turn this to static if you want but completely up to you you don't have to if you don't want to depending on how you test you might want to i'm going to go quickly and do every single one of those methods off-camera just so you have the final result when you get the code so all the methods have now been extracted you can see them here they're all very unit testable you can inject exactly what this method requires you don't have to do any elaborate setup as well so unit testing should be easier and that's what my define endpoints looks like very brief very very nice and as you can see just to prove that this actually works i can run the api again go back here list users nothing in the customer's endpoint now i create one i can list one and it goes on and every request goes through that before i move on to the next topic let's take a look at the secret source folder so the first thing is just the i endpoint definition interface this is an interface i made as part of this demo and it has these two methods we're implementing and then i have an endpoint definition extensions class with two methods here one will assembly scan and try to find everything that this i endpoint definition is being implemented by and register it in di so it's going to define all the services that it has and register it itself in di and it's going to take it here in the user points going to take it out and define the endpoints one after the other you can build on top of this and you can have ordering if you want as well and maybe checks for no service registration duplication you can go crazy this is again just an example you don't have to use exactly what you see on this video which is true for the first video as well now you're looking at this and you're like this is a neat way to do it but why bother why would i move from my enterprise way of doing things well let's take a look at this middle project here called performance test i'm using n bomber which is a load testing tool to call the old style api and the minimal api and these two apis are both running here so all style here and minimal api here and it's gonna run it for a minute each with 25 copies or threads and all it's really going to do in the test is going to try to get the same user over and over again so it's going to do a get request using an id and once this is done running we're going to collect metrics to compare the old style with a new style the two styles by the way have exactly the same logic and fundamentally code the old style is using the same repository the same model the same everything the code is the same it's just using a controller's approach instead of using the new approach with a minimal api so i'm going to go ahead here and run those load tests by the way both apis are running in release mode so let's go ahead and run the load test as well you can see n bomber starting it's gonna do a warm up in the beginning for five seconds could be longer but for local apis it doesn't really matter and now for a minute flat it's gonna try to stress it as much as it can and let's see what it comes out with in the end so n bomber has finished running it's going to dispose all the things and now we have some metrics back and let's see what we have so as you can see we did 30 000 requests per second in the old style api and the new one we did 34. so 4 000 rps more for the exact same code this is a good chunk of a performance increase like if you came tomorrow you said you can have this for free by doing basically nothing you just change the way your endpoints are called then i'll be like hell yeah let's do it and this is actually the lowest that i've gotten when i run these tests it varies from five to six or seven thousand within that minute so it just could be that my pc because i'm recording as well now is a bit more stressed so you can see how much benefit you can get for free by using minimal apis and really you don't lose anything in structure this is if you ask me a very decent way to make an api and a very manageable one as well if you want to edit one and point you just edit the one thing you want to edit if you want to add one you just go ahead and add another one if you want to add something completely irrelevant just create a new class and not those end points there it's up to you to utilize this very powerful tool and that's what i want you to take away from this video that's all i have for you for this video thank you very much for watching special thanks to my patreon for making these videos possible if you want to support me as well you're going to find in the description down below leave a like if you like this video subscribe smoking like this ring the bell as well and i'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 20,316
Rating: 4.9633942 out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, clean code, dotnet, simple api, the simplest api, how to build an api, minimal api, minimal apis .net 6, .net 6, asp.net core 6, minimal api refactoring, In defence of .NET's Minimal APIs
Id: 4ORO-KOufeU
Channel Id: undefined
Length: 14min 24sec (864 seconds)
Published: Mon Sep 06 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.