.NET 7 minimal API from scratch | FULL COURSE | clean architecture, repository pattern, CQRS MediatR

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there and welcome back to the code wrinkles channel for this brand new video botnet7 has been released just a short time ago and the minimal apisim.net6 are from my point of view very very interesting because there are some nice features added to the.net 7 version when compared to the.net 6 minimally API version and that's why in this video I want to create basically a very short but full course that will introduce you into how to create minimal apis using clean architecture with repository pattern using energy framework core with cqrs using mediator and also how to perform some very important tasks on the minimal apis like validation and like Global exception handling so stay tuned because we'll dive right into it foreign [Applause] [Music] twenty two solution in which we will create our entire minimal API application structuring it into layers according to the clean architecture principles so let's get started directly with setting up the project structure which what is usually the very first thing that I do for each new project now coming back back to this idea of clean architecture will have a very standard way to organizing things here and the first thing that I would like to do is just add here a class library and of course we'll make sure that we choose.net7 so the first layer that we want to have is of course the domain layer where we'll store actually our entities then create and it should be created just in a few seconds probably it's creating the project right now and then we should be good to go let's just remove this class I don't really need that so remove okay and here we are so we have the domain layer now let's create another one and here we'll add a new solution here once again your project and in this case still I want to have a class library and this one will be our data access layer so we'll call it data access still.net7 standard term support that should be okay so we just create it and we should be good to go also delete this class once again so I won't really have blank projects and then the next layer that we need in our application is a new project once again and this is the layer where we will place all our various commands and handlers and we'll call this application layer now in terms of clean architecture terminology this layer would correspond to what is called use cases you can call it use cases layer but in the dotnet ecosystem we usually tend to call it application so let's create a new class Library here or once again standard and we'll name this application because that would contain the application layer classes and create and then we also should be good to go with this one let's add here the delete for this class and last but not least we need the minimal API because that's the entire scope of this video or basically a very very short full course so let's add a new project but in this case it will be an asp.net core web API project and we'll call this just simple minimal API That's How we'll call that let's click on next here one thing that's important when you want to create a project that kind of like is by default the minimal API you should uncheck this box so by default if you have created regular apis previously this checkbox will probably be checked so you have to uncheck it if you also read what it says here it's kind of like makes it fairly clear so unlock or uncheck to use minimal apis that's exactly what we want to do if we want to follow with with this video then also make sure that you uncheck this one so we can then create this solution and yeah we basically already have our very first minimal API so if we take a first look into the minimal API we see that's actually very very straightforward and very similar to node.js and express like we just have here a web application in which we can register Services then we build the application and then we map routes like with map again and here this is the default in the template with the weather forecast and then we run the application and everything is okay now what I would like to do is I will simply delete everything because I don't want to be bothered by what we have in the original templates so let's just delete everything I want also to delete these comments here because we should already know what we need to do in each part of the application and don't worry I will guide you step by step and show you everything that you need to know regarding on how to configure your minimal API and bear in mind that this actually or this video is not only about the minimal API API but about how to create a solution a real solution that you could have as a template for I don't know if you start new projects on your own or maybe for your customers and basically take this type of organization as your template because because we will also concentrate into how to organize for instance the code in a minimal API project so that it is readable that it is maintainable and also easy to test so we'll look into all these aspects but before we'll get started with the minimal API there is one thing that I always advise people to do so when you start new projects when you start on new applications always start from your domain layer because that's actually where you model your application itself I always tell to my mentees that what we do in programming is we try to model use cases or things from real life into a language that computers can understand in our case by using classes so the first thing that we want to do is actually to create this computerized model of the application that we want to build and then when we have that model ready then we add to it like we have we add the data axis layer so that we are able to store to the database and read from the database then we add the application layer so that we know exactly what use cases we have like what we want to do What actors do we have in our applications and last but not least we'll also look into how we implement the minimal API itself the longer part of the video will be dedicated of course to the minimal API but before we get to the minimal API itself let's set up first of all our domain project so let's start a set with the domain layer and here first of all we will add a new folder and we'll call this for folder models you can also call it entities call it whatever you want the idea is that here is actually where we put our domain model or our core entities what we will try to build here right now is a very very basic simulation of a social network like Facebook where users are able to create a post so that's why we will add here this class and we'll call this class as a post because that's we want to actually model in our application right now this will actually be a very very simple post here we will make this public because we will need to use this class also in other layers and I have already prepared here are some properties of this post as said it will be a very very simple entity we don't want to concentrate on all the domain stuff if we want to have well a better understanding on how to model domain I have plenty of videos on this channel on the channel on this topic like what's the rich domain model what's an anemic domain model how to structure models and things similar to that so we have already covered those topics and we just want to have something to get started with it very very quickly and that's basically our post it has an ID then we have a string which is which contains the content or the post content and yeah let's make it even nullable and we have a date time which is the date created and the daytime which is last modified those properties kind of will never be updated by clients or by consumers they will always be updated by our application itself because there we know exactly when we need to set the created date time and when we need to set the last updated the time that's actually what we will do and what we will handle in our repositories and this being said actually we are already done with the domain layer we already have the entity or the core domain model that we need for our application right now so we can just move over to the next layer that we would need and this is actually our data access layer now in the data access layer the first thing that we need to do here is we need to install some nuget packages so let's do that and the nuget packages that we need here is first before Microsoft Entity framework core so let's search after it because that's what we need to install here now the things that we need here is Microsoft Entity framework core like the core library and make sure that it's also on version 7 because we are on dotnet7 here right now so we have to keep those two in sync if if we want everything to run correctly and then we'll also need the SQL Server from Entity framework core because that's kind of like what we will use underneath and we'll have a database in visual in SQL Server Express it kind of like shipped ships with visual studio and P I guess for the data access layer right now we should be good to go so the first thing that we can create here in the data access layer is of course a class for our data context and let's call this class that we have here so social TV context because it will be a social media application so we'll call it social DB context we also need to make this public because we'll need to add the DB context also to the DI container and this means that we have to access it also from another layer so we need it as public now to make it as a DP context we just have to kind of like inherit from DB context but for this I also need to spell it correctly but yeah this is done now we need the Constructor because we'll use this social epic context with dependency injection and we have to pass in the DB context options that contain our connection string actually so we'll have here the big context options and we'll have to pass those options of course to our Base Class which is in the in this case our DB context so we as in the options and that should be it now the next step that we would need to do to set up a DB contest is of course we need to work with this entity which is post we have public and we'll have here a DB set of post here we'll need also probably a reference to The Domain project and have a using statement here and have ADD reference now we should be good to go and we'll call this posts but also let's type it correctly and that's a property so get set and yeah that's more or less our DB context that we did now the next thing that we will have to think about in the data access layer is that we kind of like need to create the repositories but in order to have repositories what we would need to do is well actually we want to have who have an interface as said but where do we place this interface that good question and the answer is by the way there's also a video on the dependency inversion principle on the code request channel that will explain or that it already explains this in very detailed way but the main idea or the core concept here is that the interface should always be owned and defined by the client client meaning that layer or the package that actually consumes it or that needs that functionality so in this case where will we need the functionality of repositories what layer will actually work with the repositories to get some data and do something then with the data of course it will be the application layer so in this case we'll also go to the application layer here we'll add a new folder and this folder will call abstractions let's make sure that I also spell it correctly uh I guess it should be fine and here we'll add a new class and we'll choose to be an interface and we'll call this I post repository something like this but maybe let's just use the singular forms of post repository because because it is a repository for our host entity but once again I have to also type it correctly now it seems to be fine and also we'll need make this interface of course public because we will actually need this interface in a total different uh layer and what I have already prepared so that I really don't have to write a lot of code here that we don't need is kind of like all the things that we need to implement here first of all of course we will need to add a reference to the domain because the post is there and now we should be good to go so it's a very standard repository with all the crowd operations that we want to implement also in our minimal API of course we have this get post with comments uh okay actually that one we will not have because we'll we will not have comments we'll have here get posts uh or let's call this get uh all posts something like this and also yeah we don't have this concept of comments here right now so get a post by ID so in a post ID code and create post update post and delete post and we should be good to go with the interface definition for the repository and the implementation of course of the repository will have in our data access layer so let's go back to this layer and create a new folder here and the folder we'll call repositories and in this folder we'll create a new class and new class and we will call this class of course a post Repository we will need to also make this public because we'll need this in the application layer actually even though in the application layer we actually just use the interface but we need it for dependency injection in the minimal API and this would Implement I post uh repository so that's that's what we Implement here and of course here we'll need to add a reference to our project as a reference to application that's exactly what we want and then we can even uh just wait a little bit so vs 2022 is version 17.4 is actually very very very slow and I don't exactly understand why but virtually that's our repository that we have right now cool now I also have here prepared uh some things that we want to actually Implement so the first thing that we want to implement is this create post but before we get started with the implementation of these methods we have to make sure for instance that we'll have here a private read-only well social DB context so that's rdb context that we want to use and we'll call this CTX and of course we will also need a construction for this and in the Constructor in the in the Constructor we want to have uh social DB context context and then we just need to assign this here like this and we are good to go so now we are set up it means that we will when we will wire everything up with di it means that each time that we actually need an instance of this post repository an instance of the social DB context will be injected in our repository so this means in turn that we can now concentrate on creating or implementing this type of methods we have here this async task create post so what we do here or what we need to do here is well just to create the post um okay let me just uh just did I name this let me check here um yeah we need to name these posts because that's that should also be the name of the table in the SQL database so right now we should be good to go with this so the logic for create post is very very simple we get a post here that needs to be created we get it as a parameter to the method then we manually set the date created so that's the place where we can Define okay when do we need to actually update the data created and the last modified so we just do that the post content should already be there so we just add this post to the post and then we await and save the changes and we return the post that was actually created Because by the time it gets created in the database this post will also get an ID we have to return it so that the consumers or the colors of this method would know exactly what id was generated for the new post that was added to the database so it's very very important that we return this created post to our consumers or to add to whoever actually wants to use this method and then the next one that we need to do is we need to implement a delete post and I have also prepared a code a code snippet for that we'll walk through it of course but it would take really really longer in order to well implement it from scratch now the only thing is that we need to make this method async and uh yeah here we don't want to include the comments because we don't have this functionality right now in this application and a first or default async so um yeah the idea is that we kind of like um don't need to do this but here we'll have to change because from post um actually what we want to do is if we get the post so this is first all default if post is now will return out because we cannot delete it but if everything is okay then we say context.pose dot uh remove and then we can just specify the post that we just got from the database and say that this needs to be removed and then we await and the save changes and then everything will be deleted and that would actually be okay now the next thing that we need to implement is the get post the get post like the list of posts is very very easy to implement because here we can just uh also of course we need to make this method async first so it's async task of a collection of post and then we return uh CTX uh the posts and we can just say that here well um two least async we just want to return it like that now eventually if we don't really want uh return a weight of course CTX post released async if we want to not return the list directly we can well Define in the interface that we return an innumerable here and then in that case we can just return the post DB set and that would also do the work the difference is here that when we use the tool is async ef4 actually buffers the data so it's loads it into memory when we use the innumerables or the variables so just the ctx.posts then it actually streams the data so it's not loading everything into memory so keep this in mind if when you're thinking about how to optimize in your queries uh that might be very very important now the next thing is of course that what we want is to get a post by ID that should also be very very easy to achieve because we can just return the weight uh ctx.post and here first or default async so that's what we look like need to do and here we are searching for a post that has the ID equals to the post ID that we get here as a method so yeah let me just do this here of course there is here a slight uh well warning here because this can return null and we haven't turned off the nullable reference type feature so this is why we have kind of like this green squiggly line but it really doesn't bother it or it really doesn't bother me too much right now and then the last thing that we need to implement here is this update post method in the repository so we have updated this one uh what we do here of course like we get a string which contains the updated comment and we get an in for the Post ID so what we do here in this case well we look for the post of course but then we just don't need to include the comments once again so that goes that code snippet is not actually what we want and of course we need to also make this method async and now everything should be okay so now what we do is we get a post from the database is that's uh that's okay now if we have this post then we set the last modified bit because we update the post so we need also to to change that property and then what we have here is updated the content like that's what we want uh to update for the post and then we await the save changes and then we return the updated post and that's it we have actually right now implemented our repository now we can even make things a little bit cleaner just remove the things that we don't need here like these ones so we keep everything as clean as possible so I think that we might right now be good to go with the next step of implementing our application and the next step that I would like to do is I would like to finalize kind of like this creation of the data access layer by adding HD framework to our minimal API project because we need that in order to be able to run a migration and to update the database so this is what we'll do actually as a Next Step do this we need to head over once again to the minimal API project where we have everything set up and by the way guys I already have a database created and I have already added the connection string here as my default property for the local DB where my database is created which is this minimal API course so this is already my database it's a blank database so there is nothing in it so far and what I want to do is well we want to test actually that our migrations work with for the data access layer and that we are able to update the database and to do this well we have here a regular stuff like we want to add different things here but of course we need to add some nuget packages for that it's like standard way of adding the DB context and repositories to your service collection in a regular.net 7 application so even if you have regular API with controllers you will you would do this exactly the same way so there is no real difference when it comes to Services registration it it works exactly the same now what we need to do of course here is we'll need to install some you'll get packages as well so let's go here to nuget packages now the packages that we need here because what we want to do is we want we want to add migrations and update the update the database and to achieve that we'll actually need some more packages compared to what we had let's say Microsoft Entity framework core what we have in the data access layer so first of all we would need the regular asp.net core not identity uh why is it okay sorry I have doesn't hear something wrong and Microsoft Entity framework core that's what we actually want to have here and yeah we need to add this package once again we make sure that it's version 7 because it's the.net 7 minimal API so we have to be consistent this is the first package that we needed then the second package that we need is of course the SQL Server package because we are using SQL server and it's still very very slow Visual Studio sorry for that so let's also install that package and there is one other thing that we need we need the tools because this is the package that's kind of like used in order to be able to uh well add the migrations of the database and things like that so let's also install this package and then from The Entity framework core perspective we should be good to go so okay all packages are edit let me close this one and here of course we'll probably need to add some usings here we also need a reference to our data access layer so add the reference to the data access because there that's the layer where we have our social DB context use SQL Server this comes from Microsoft Entity framework core so we will use it like that and then the I repository that comes from the application layer and here using application abstraction so that should be okay and then last but not least the post repository that also using data access repositories and in that case we should be actually good to go so right now we should be set up so let's go let's head over to the package manager console which is this one and what we need to do is because we have let's say the the project that kind of like is the entry point to the application is our minimal API but the project where we want our migrations to be is the data Access Project so in this case we set here the default project to the data Access Project now let's say here add the migrations initial okay and we have a problem at the migration sorry with DOT s uh so that should be good to go so right now it's it's building hopefully it builds uh okay hopefully we don't have any build errors and hopefully that the migration will be created very very soon and everything will be okay it's well build was successful so that's the first very important thing uh okay one other thing that we need to do for the solution and by the way that's important so we go to the solution properties and we need to set the startup project because by default it will set to the first project that we have added to to our solution so we have to change it this to the minimal API and since we are here there is another thing that I would like to do on the Cs Pro File like if we click right click uh the minimal API project and then go to properties there is one thing that I would like to do when this page loads of course I want to go here to debug and here we need to well uh open the background profile because this is what you need what they want to do is I want to get really rid of this idea of launching the browser uh when we start the application I don't really want to launch the browser I want to have or to use Postman in order to be able to actually test the functionalities of this minimal API so that's what we actually have done here so everything should be prepared right now let's give it another try then so add migration initial now the build will succeeded it was faster than the first time and yeah we see that here we got actually an initial migration to this and let me check if there are any problems with this file but hopefully not no everything seems to be fine and then it just creates the table with the post with everything that we have defined so nothing really complicated there so then the next thing that we would like to do is update database to build circuits it builds again it should also be successful and indeed it was successful and we can see that uh yeah it uh it has executed correctly we have created a table so create table with all the stuff so it means that the table is right now in the database so this means that we are good to go from the point of view of the data access layer now there is last layer that we have to take care about before we move to the only the minimal API stuff and that's the real application layer and as I said we want to actually use mediator for that so it means that we will have to set up mediator now the idea is that the queries and the commands and and the handles for them will all be in this application layer so it means that what we need to do here is we'll go to manage nuget packages and we will need to look for the mediator package however here there is one thing that we need to always it's not Microsoft is a mediator Jimmy Bogart's Library very very popular libraries so yeah we have here the mediator now here we have to pay attention to one thing like we have here two different libraries or two two different packages here or nuget packages one is mediator which is the core mediator functionality and the one the other one is mediator extensions Max of dependency injection so this is a package that contains extension methods that allows us to register the mediator with the di container now in the application layer itself we just implement the core let's say Secrets logic like we we have a Commons we have queries and handlers so we don't really do anything with the eye there we just create our commands and queries so in in this case we would need here in in this assembly only the mediator so the core library of the mediator however and that's the very important part is we want to add our mediator or the mediator to our di container there is one other thing that we need to do and is let's go also to the minimal API layer or project and also manage nuget packages here and we will also need to install mediator here because here is here is the place where we actually want to register the mediator with dependency injection and therefore of course we need this package here like mediator extensions dependency injection because that's what we want to do however it's important to note that when you install this package the well core mediator package will also be installed with it so uh yeah that's kind of like uh the reasons why we here we just need this one because we need actually the extensions for editing mediator to di or to the dependency injection container cool so we have added this now the last thing that we would need to do probably here is to also make sure that we would be able to kind of like also add mediator to the eye but in order to do that let's first of all create a few you comments here because that's actually or queries and and the handlers because that's actually the the important part that uh that we want to do so yeah let's head over to the application layer and the way that I like to structure an application layer is that I want for each type of functionality to have a dedicated folder in which I will paste in all the queries the commands and the handlers and if I need anything else for that specific feature so that's why the first thing that I'll do here is add a new folder and I'll call this folder posts because that's the post functionality we will have all the comments and the queries and the handlers for this post functionality so this means that here I will have also some or a bunch of subfolders which would be the queries first of all then we'll add a new subfolder and this other subfolder will be let's call it uh commands then what we will actually need for the senders I guess we'll um we will create dedicated Handler folders so uh sorry in the post here we'll add a folder for comment handlers like this and we'll also add a folder for the query handlers so add a new folder and we'll call this query handlers Okay cool so let's start with a comment because in order to get the post we just need to create one first so let's start with a new command and that would be add new class and in this class and we'll call this just create post because it's clear from the naming it's create post it's it's a command we want to do something we want to actually change the state of the application of course we will also need to make this class public so it will be public now what we will do here is we will inherit the I request which is the interface from mediator that kind of like describes what a request is and this is a generic method um or this is a generic interface where we have to specify a generic type parameter pointing to what we want to return from this command and we want to return a post that's why it is an I request of post now when we create a post if we have looked a little bit at our data model is actually we have the ID which is generated by the database we have the date created and the last updated that that are always handled by the repository so the only thing that we actually need to do or to use uh or the only thing that we need in the comment is actually a string that represents the post content so it would be public string and let's call this post content and yeah it's a regular property we can even make it nullable to make it clear anybody that this might be null however we will Implement later validation and really make sure that this will not be null actually and then we can clear everything up we don't need this stuff anymore so let's just uh click that cool so now we have this one with create post um and then we need a Handler for that so let's add here a Handler and we have a class here and here we'll always create post enter and the Handler so in mediator to implement the Handler for a certain request well first of all we will make this also public and here we need to implement the I request Handler interface also coming from mediator and that's also actually a generic interface and we have to specify two type parameters the first one is the command for which this Handler will handle the request and then the return type what will it return and we will return post um okay here of course what we need to do is we'll need also a using for the domain and then we also need to implement the interface and yeah that it would be it now the first thing we will need to do here is we'll need to make this async first of all because it will be async and then obviously what we need into a Handler is always the repository because we use the repository to perform stuff so we'll have a field here private read-only field that would be of type I post a repository and uh yeah let's call this uh I don't know how how we should call this posts uh repo let's call it like this to be clear what we actually want with that and then we can have the Constructor and in the Constructor we just want to inject the repository because we already I uh post a repository and let's call this post repo like that and then if we go here basically we can already uh do the stuff that we need so assign what we get from the DI to our private field and that would be it now for the Handler of this one let's uh let's use some code that I have already prepared just give me one second uh here it is so of course we don't want to throw a not implemented exception that is always bad in the sign that we are not using the interfaces the right way what we do here is actually we create a new post and for the new post we actually will we add this data created or the last modified however thing is uh what I would like to do is actually we should remove this from here and the new the new post that we need to create should contain only the post content and we have or we'll head back to the post repository and for the create post because we already set these days here so we have done this correctly but then in this Handler we don't need those tests because they are set by the repository so in this case we are actually good to go we just await post triple create post and yeah we provide a new post and then the post will be created which is very very nice cool let's now Implement all the other comments that we need for a full crud and those other comments are for instance the next one would be the update post so let's have here one and we'll call this update post because it's clearly what it is about um so what we'll do here is uh let's make it public first of all that's a very important thing here and once again we need to inherit this I request and to specify what we exactly want to return and we want to return an updated post of course that's also what we would need to using domain models now the thing that we need here is to update the post first of all we need to identify which post we want to update so we will need an integer not a post public the inter Port ID so this is the first thing that we would need in this command and then what we need of course is the updated text or the updated content of the post so we'll have here public string uh post content get set and we should be good to go with this Command right now okay cool let's just remove this top that we don't need so we can close this and then we can create a Handler for this so let's go here and create a new class and this new class should be update post Handler and of course we'll also make this public even though we need at least one that needs to be public theoretically all the others could be internal however we will keep consistent and yeah we'll have those public so I request answer that's what we need to implement once again this is a generic interface and we have to specify two generic type params the first one is actually what we want to or on what exact comment or request this Handler should handle as the name implies and that would be the update post and what it will return which is an instance of the updated post so we also need a reference here to The Domain and uh yeah we we have that right now and then we need to also implement the interface now of course what we would need here is once again um we can take it from here so we need this uh private uh field because it just needs to contain this um this repository for the post and what we'll also need here is a Constructor and in the Constructor we just need to have the I post repository uh post repo like that and then of course here we can just uh well add what we need posts repo equals post repo I wonder why Visual Studio didn't uh really gave me the suggestion to just complete that already because yeah that's that's how it should actually uh work now here the logic for this will be also very very easy because we have the repository that does all the stuff the only thing that we want to do is here uh yeah of course we need to make this async also so yeah done so we have fixed this then we just well uh use this post repo update post we provide the content and the post ID and then the post should be updated and we are once again good to go with this command now there is one final comment that we need to implement and this would be the delete uh post command and delete post so let's set keep consistent consistent and we'll have public class delete post and that would be an I request and here in this case we don't return anything so it means that for the delete command uh we will not return anything so we'll just have this I request of course we will need to add a reference to mediator do that and the only information that we would need in this command is the ID of the post that we need to delete public int post ID something like that and we should be actually good to go with this one now I have a problem here what's the problem here okay with because it's post triple so it should be okay right now cool uh let's go back to this update command uh because uh not update delete we were working on a delete so delete command is actually ready just remove the animated stuff here and then we just need the Handler for that to add a new class and in this case we'll have this delete post Handler and yeah we'll also keep it consistent public as delete post Handler and that will be an I request Handler off delete post because here we just have to specify what we want to do or what what this that should actually handle then we need to implement the interface now the only thing that we need is once again we need here this repository so we will take it from there um let's let's just make here just a bunch of space Also we add this one let's add the Constructor and in the Constructor we'll add the I post post a repository posts repo that and then let's just sign everything and we should be good to go with this one now the only thing that we need to do here is of course make this async because it will be async now mediator when you don't return anything it actually just returns a unit the unit is just well a struct that represents a void type because you cannot return void from tasks and this is how mediator has decided to actually handle uh this type of of scenario now for the for the delete itself like the Handler it's really also once again nothing very very complicated the only thing that we need to do is just use the repository and delete the post uh here of course we just need to make this correct and then return unit dot value which is actually the unit cool so it seems that we still have an error somewhere I'm not sure exactly why update post to return vision for update content okay uh I guess we call this uh post content okay so yeah now now we should be good to go now we shouldn't have any error so we have all the comments implemented right now so uh then we have the next thing is we have the queries and after just a few more classes we are ready to actually head over fully concentrating to the minimal API let's call get all posts so this is the first query that we need and uh yeah we'll make this also public and then this will be an eye Quest and it what it will return this I request will be actually an i election because it will be pro pro probably a list sorry for that it would be an Eye collection of posts probably we'll need to add some using here of course they're using the domain now for this get all we actually don't need any information right now so we don't actually need to populate the class with uh with anything now this means that what we can do here is we can head over to the query handlers and add here a new class and uh we'll call this class get all posts Handler which should be something like that well that would be a public as get all post Handler and this would be an I request Handler off first of all we need to specify the query so get all posts this is the query and I will specify what it should return it should return an iron collection of host so that's actually what our Handler needs to do now there are a few things that we need probably to add as using here the domain models and then we'll also actually okay but here vs is also playing uh crazy because theoretically um that it should be it should give me the option to kind of like Implement uh this interface but uh yeah in that case it just doesn't do that so yeah let's let's maybe just do this here get all posts Handler so let's open this again and yeah in this case now it works so the perks of using visual studio and these things have happened so let's have this async now the one thing that we need here that you can copy over from the Handler is of course the field that contains our repository so let's just move it here and yeah let's use it that's the repository let's add the Constructor to that in the Constructor we need I post a repository and let's call this post uh repo and then we can just assign it here but it will be a post uh repo and it should be like that however I always like to have here a space between those two so I will just add that now for this one for the get all post which is the Handler for this actually it's also very uh very very uh easy to implement because what we need to do here is just return the weight uh post repo dot get all posts that's kind of like what we need to do and yeah we should be good to go with that and the last query and the Handler that we need and then we'll head over to the minimal API uh it's query for get post by ID get post my ID so that's actually it let's once again keep it consistent let's make this public then get post by ID and this would be an I request and this request will return the post that we actually want so let's also make sure that we need uh this domain model now the next thing that we need to do here is if we want to get a post by ID of course we need to identify that post by the ID so that's why we'll have a public int post ID I want to make it make it explicit so I know that it's the post ID not just ID as a general ID so it's the edit of the post and therefore I prefer to kind of like name this property like this so that would be the request just let's remove the stuff here so we don't need it anymore and then the query Handler for this one and that would be here at new class uh get post my ID Ender that would be the class name once again let's make it public first then let's inherit I request enter and once again get post by ID is the query that we want and what we will return is just a post so in this case it means that first of all we will need to add the using for our domain and uh second of all we will need two just Implement kind of like this uh well get all posts let's just keep this um let's maybe just copy over everything from here and just change the name that we actually used there because that kind of like it's the only thing that's kind of like different so instead of get all post Handler is get post by ID Handler get closed by Eddie Handler so now it should be good to go and of course the only thing that we need to do here is we can just go here and say return wait of course we need to set the async keyword then here and yeah we have made this as an async method so post repo dot get a post by ID where is it get post by ID it's this one and we just need to provide the ID which is the request dot post ID that's what we have and yeah we are right now ready with our application layer so let's maybe just I don't know rebuild the entire solution to make sure that everything works now before we head over and concentrate only on the minimal API itself there is one last thing that we need to do we have to wire up the mediator and the command handlers and the commands in the query and the query handlers we need them to wire them to be wired up in dependency injection container so this is why the first thing that we need to do here is we should go here to the minimal API here we have this program.cs class and in this program uh dot CS class what we need to do is kind of like just add for instance um to the team what do we need to build our services that's coped and uh yeah admediator and here we have this create post but we did name it just create post code that uh that should actually do that for us right now so we have this create post application post comments and yeah that's that's where we have everything so right now what we have done is we have added uh the mediator with everything that we actually needed cool so the next of the step is that we have to start actually build out our minimal API and then create the endpoints and that's exactly what we will do next the first endpoints that we will create are the endpoints for retrieving a post by its ID and the end point to create a post and the reason for that is because obviously we need to add posts in our database so that we can use all the other endpoints but then again the other part is that mean when we want to create the post we need to return a 201 created result that will also contain a location header with the exact resource or the exact URL where clients might be able to retrieve the newly created resource so in that case we need to First implement this this getby ID and then the create post so let's get just right into that first of all we have this app after we build it we have a web web application now my idea is that it would be probably best to end or you or to map all your endpoints actually just before the app.run part because here the other part you should reserve for registering middleware middleware actually work exactly like their work also in regular asp.net core apis with controllers and in fact at the end we'll also look into a very useful middleware that we will Implement here in our minimal API application but let's get started so the first thing is or we suggested is that we should have here this map get because we want to have a get and that's how you map a get endpoint now when you map an endpoint in a minimal API there's actually two things that you need to provide first of all you need to provide the exact location where uh this endpoint or the route for this specific endpoint so in our case it would be API slash posts a post and since it will be a get by ID we have to also specify the ID as a routing parameter so just like we do on the route attributes in regular controllers now the other thing that we would need to provide is of course is well the Handler so when we have a request for for this specific route somebody should handle that like the way that we have the command handlers and query handlers in our application layer it's exactly the same concept we have here route and for that route we need a route Handler a round handle in a minimal API is virtually a method now when we talk about this type of methods there are some different ways that you can use them now the first and the most obvious thing that you could do is just use a Lambda expression and that's what we will do in this case because a Lambda expression is nothing else actually then an unnamed method or an anonymous method so we can just use it here as a route Handler now there are some things here so first of all we want to have this as an async method and secondly we need actually to bind for instance these parameter that we have in the URL we need to get it somehow in our route Handler the thing is that it is really similar to how things work with regular controllers because the only thing that you would need to do is actually here just specify an INT ID we should make sure that kind of like this matches this so this should be an exact match and then um basically.net 7 when will have or when will have a request with this route it will map the number that will come here it will map it and place it as a parameter in our method so that is how these things work now the second thing that we have to think about is how do we get our mediator here because in controllers we usually inject them in the Constructor of the controller and then we can use them however Constructor injection of course is not available in.net 7 because we just use here some methods that we defined that that they are actually the handlers for a specific route in this case we cannot simply use Constructor injection but we can use method injection and of course it works exactly the same like the Constructor injection in the regular apis the only difference being that of course we need to specify what we need to inject also in as a parameter for this method so we'll have I uh mediator we have also to type it correctly and then we have to also Define them or separate them by a comma and here of course we'll need to add okay um but I don't want the mass transit so yeah I guess I have named it wrong I mediator yeah now it works so everything is okay right now so what we have done is once again when you think about dependency injection in minimal apis you always inject in the construct or no not in the Constructor but in the method so we have method injection we don't have Constructor injection here but other than this it works exactly the same it's the same dependency injection container and it will provide you all the information all the register Services right here uh when you need them now the one thing that we need to do of course is when we have this kind of like um uh method what we need to do is okay we need to implement logic what would happen here when this method gets executed so when we have a request for this route and the answer to this is actually very very easy because the only thing that we need to do is we just need to create a query and from that query we need to send it to the mediator so let's have here for instance for this VAR uh we get a poster get a post equals new uh get post by ID and then in this get a get post by ID we have the post ID equals ID so it's exactly the same that we have here now what we need to do here is this is actually the query then we need to get the post work post uh and this equals to a weight mediator dot uh not publish because we don't want to publish notification but instead we want to send a query and uh yeah we'll send in the get post of course uh so that that's what we do uh called so we are good with that now the only thing that we need to do when everything is done we need to return something so what we'll do here is return and here is in the minimal API we have this results class and this works actually you can imagine this class as being something similar to what we have or to what the I action result is so it has basically more or less the exact same methods that we can use so if we want to return okay we just return okay and then we specify okay what would be the body that we want to do or to add however there is one important thing that we need to do here and when we create such endpoints in a minimal API we can actually add to them a lot of information like that would be called the endpoint metadata it's called like that even in the.net 7 minimal API documentation and that metadata is important in certain scenarios now in our scenario why the metadata is important is because when we create a post we want to be able to return a created result and to also very easily specify a location header or where exactly that newly created resource can be accessed and in order to do that from the create Handler we have to reference in a certain way this map get for the Post by ID Handler so that it knows it so the dot Net 7 knows exactly how to build kind of like that API and to place it in the in in the location header and to do that the easiest way to achieve that is actually to have uh use this with name information and here we can call this for instance get post by ID we have specified this metadata information now this means that what we can do now is we can come here and say app.map.get not not get but it's Post in this case we'll map a post because this is where we want to create a new post so first of all once again we need to to provide the route and that would be once again API slash post which would be the same and then we kind of like need to provide the Handler for this and we'll provide it also as Lambda expression here now also this one will be an async and then what we need here is uh we'll need also a post from the body but we'll also need the I mediator that's we need it virtually everywhere so we have the mediator and then we have the pose from the body and it works exactly the same like in a regular controller so like if you say here that I want a post it will look into the body and check if you have a post there and or or it will take the data that it will it that it finds there and will try to map it to a body now this all will or would also happen by default but if you want you can even specify here exactly with this attribute from body like specifically look in the body so we want to be very precise and very exact and in this case we can specify that however there is no need need to really do that because.net7 will know exactly how to look and bind your parameters some of them will be injected from the DI container and this one for instance will be taken from the body so in this case we are actually good to go with this one now what we need to do here is uh well we can just create the post and here I have the code snippet for that so we have a create post and we have this create host which is the comment that we just have to remove that then post content is equal to post content so it's exactly um yeah the content that that we get from from the body then the creative post we await and send it to the mediator that will return as the body and here is how we then return the 201 created result we also use this results class that's as said is actually kind of like the replacement for I action result that we have in the controllers here we call these results there are also other options and I will show you the other options just a little bit later because we really need to be aware of that other options and what uh what Pros it actually brings to the table because it's it's very important but for now let's get a custom and concentrate on these results so we returned and created at the route and then what we have to specify here is the name of the route and that's why we have specified here which name get post by ID and in this case we have to make sure that it's exactly the same because otherwise the naming will not match and we the 2007 will not be able to construct the location header then similarly to what we to when we create a created result in a regular controller we need to provide an object that will contain uh the parameters or the routing parameters like we need the parameter for the ID so that's what we provide here and then once again the body for this and this is how we return this created result so we should be good to go with this one now let's also maybe implement the other methods so app.map.get so we want to implement this get all so let's let's just think a little bit about that uh first of all we need to provide the route so it would be once again slash API slash post but then it is by ID so I guess we should be good to go so async and we'll also use this Lambda expression once again and later I will show you how we could do this differently actually uh cool and then what we have is that get all posts so um yeah that's it's also something that we can have here like get comment get all posts and then we have the mediator of course we need the mediator we need to inject it I mediator so it's this one and yeah then we can just send everything and then we return and this is the typed results but let's change this to results right now and we'll go back to what the type result is just in a few minutes so this would be the get now the only thing that we need to still Implement is or are actually the app.map put for the update now for the update what we'll have here in the route is first of all yes slash API but I have to hit also the correct keys on my keyboard API posts and then we also need the ID because uh yeah we need the ID of the post that we want to create now uh let's just also add the Lambda here so async and we'll then just populate it with what we actually need and here there is one other point that we have to be a little bit careful about so we will need the mediator we see that we need the mediator basically everywhere so uh let's add uh the mediator mediator so it's this one first but then uh here there are a bunch of different other things that we need to map so we will need to also map from the ID or the ID of the post and we also have to map from the body from where we actually received the updated content now what I would like to do and we'll see a little bit later why this is important the other endpoint where we actually get a post from the body is this is this create and I would always suggest you when you have this type of situations where you kind of like have something that you get from the body and you want to map it to to your own type that you will use then with the repositories make sure that in all the methods for in all the route handlers where you actually need that to place them at the exact same order that they were placed previously so previously this post was paid was actually placed as the second parameter here so we'll have to make sure that is also the second parameter here so it's a post and then we'll have this ID in ID which would be the routing parameter and we'll see just in in a few minutes why this detail is actually very very important when we will talk about validation cool so right now what we want to do is just update this post so what we'll do here is we'll just use the code snippet that we already have now here the command in our case is just updated post so it's just what we had previously like we have the ID uh um I guess this one we have called post content here so we could change that and yeah we right now should be good to go updated post await mediator send and after we get the result back we return a result okay and this updated post which is actually very very nice and the last method that we want to implement or the last route or the rust endpoint app dot map Elite because that's that's actually what what we want to do here now as we have seen previously what we need for the delete here is actually just the ID so we'll have slash API slash post slash and we need this as a routing parameter so we'll place this then in um angle brackets in braces but it should be called ID to be sure that everything is consistent then let's use the Lambda here for this delete now the only thing that we need to once again here is the imediator so let's just use this mediator and we also need the routing parameter that would be an INT and it would be a ID and now for this result I will just take it and then also use the code snippet that we have here so it is the delete post and then I guess we should be good to go so we create a comment for that we use the mediator we sent this and then uh we return these results no content so that's it we have implemented endpoints for all the crowd operations on this post resources now I have also opened and prepared Postman with the collection of requests for this minimal API so let's see if things are working well let's run the application first and then uh well it may be will take just a bunch of seconds until it gets created and when everything should be fine I guess right now so we can just go here so as you see I have this minimal API course and I have here a collection of requests here is for instance to create a new request so we have a post to the Local Host where we have this application running API and posts and the content for this post would be my uh first post uh although I guess there might be a slight problem here so uh let me just stop this and let me just check again because here is post and the content and uh let me check the post here uh it's still running why is it still running I don't want it to be still running oh cool so yeah let me look a little bit into the post that we have here uh so it's it's content it's cool uh we are we are good with that and here it's also content so yeah we we should be good to go I was thinking that maybe I had a different property namings so that was my fear I had to double check that let's run this again right now and uh okay try it out so first of all we want to create a new post so we have to send the request we just wait a little bit and hopefully hopefully we get a right response to our request it goes to the database the first time is a little bit slower but we see that we get a postback and if we look into the headers here where are the headers here are the headers we see that we have this location and they say that we need to be able to retrieve this post in the location that's uh API post and the id1 let's try it out let's go to this endpoint API post uh let's change this ID to be a one because this is what we want to get and this time I guess it should be a little bit uh more or quicker and indeed so we did get everything that we wanted let's uh let me just uh to to play around add another post my second post and uh yeah send it and uh I have created that so if we go to the get all posts I guess we should be also able to retrieve the entire list so indeed we have a three of them right now let's also create a third one so we had two of them so let's create also a third one to my third post and this third post is has the ID3 now let's update something so we want to update the post with gay D3 and here I have here my first updated uh let's say my third updated post because it's the third post that I want to update so let's click Send and we see that it was updated so if we get all posts once again the third post is my third updated post so it it was correct and now we can delete it and we want to delete the post that we just have updated so let's delete send Return To Zero for no content so it seems to be right now if we go here and we run this we see that the third post was deleted so indeed we just have two posts right now in our database so everything seems to be working okay cool that's really really great but even though most of the tutorials that you will find online will probably stop at this point my goal here is to kind of like I said uh give you an option or something like a template that you can use as a source of inspiration whenever you need to create maybe a minimal API project maybe for your customers or maybe during an interview and there are some things that we need to be careful about because when we create minimal apis we have just implemented right now regular or very basic crowd operations on only one resource the problem is that we have added a lot of code in our program.cs file and that's for sure not something that looks good it's for sure not something that's readable and it will become less and less readable with more resources that you add to your minimal API so this idea of just mapping endpoints in the program.cs that you see virtually in all the documentations and they don't foreign it's not something that we will do in real or regular applications that we might want to create with the minimal API then again the same goes also for this other part where we register Services because yeah in this case we just have one repository we just have one DB context in the mediator but when you create a real application with several different resources you might have a bunch of different repositories you might have a bunch of different other services like you would like maybe to to configure authorization policies or a lot of different things so probably this part will also get longer and longer and longer and easily or step by step this program.cs file will become unmanageable and unreadable so the challenge is here right now okay let's find some ways in which we can refactor this code to be more readable and easier to maintain so this would mean that we kind of leg would have to split these different parts in a different let's say dedicated classes that are only responsible to perform a certain type of thing and I would suggest we should start first with finding a way to actually move kind of like these service registrations out of this program.cs file maybe in a different file or we'll see exactly how we'll do that but that also allows us or gives us the option or the freedom to actually maybe if we want to group adding different services that kind of like belong together and have them all in separate methods or on or in separate classes even and the end goal in the end is that what I would like to have here is that I would like to have only one single method that I will call here on the maybe Builder and that will register all the services that kind of like it finds in my minimal API project or maybe or even in other projects so let's see into a few options in which we could achieve this the easiest way to proceed here is from my point of view to use some extension methods and therefore we'll go over here and add a new folder and we'll call this folder extensions this folder is right into our minimal API project even maybe here just rename it and also add an S at the end because we'll have probably different type of extensions here and we'll create a new class so here we have add new class that should do it and I'll call this class minimal API extensions and we'll see exactly in a while probably why I want to call this minimal API extensions now the first thing that we want to solve is of course for the extensions we need the correctly static so we'll make it static of course and the first thing or the first part that I want to resolve and declutter my program.ts file is to actually register the services so for that I will create here a static method public static it will return void of course and I'll call this method just register services now this extension method actually and that's a very important part and we'll see just in a few seconds why is not only I service collection because services are usually used in the I or are added to the I service collection or on the iservice collection however in our case if we just take a look here we see that in order to add the DB context we need to also access the configuration to get the connection string and the configuration well is different or is totally separated from the iservice collection now this is why we'll have this extension method on this web application Builder and we'll call this Builder like it's called also in the program.cs file and here we have this one right now we can just go over here really cut everything and move everything into our method that we have created here so this extension method now we have some uh some errors here okay a builder okay because this Builder verification uh that is not something that we should have cut from there so and you see this is a reason why copy pasting code might not be such a good idea and in this case I just wanted to well have a little bit more time and be more efficient because this video already probably is a lot longer than I would have expected still here we have this web application Builder and on that Builder we want to actually do all the stuff that we previously were doing directly in the program.cs and this means in turn that we can come back here and we can just say here Builder and here register services and that's it now all the services are moved away and everything should be fine now the idea behind this is of course we just have here A bunch of lines of code and just a few bunch of services but in reality what you can easily do is actually you can have this public static void method with registered services but then if you have more services that you want to add that you can that you might be able to group in different logical groups you can then create private methods for each group and then in this method that will only be an orchestrator that register or you can have registered database Services register utilities register repositories and you can just call those methods here in this one and this one will just orchestrate what services exactly need to be added and in this case from my point of view or do by doing this the code will become more maintainable and easier to understand and also of course easier to read therefore so the first problem is actually solve with the services that was actually quite easy now the only other problem here is and I guess we can just also remove from here some stuff we don't need this anymore we don't need this using here anymore it doesn't really do anything and we also don't need this anymore because everything is moved to the other file and now comes for the more trickier part because when it comes to this one to mapping the endpoints things are a little bit more difficult now for instance you can imagine right now we have for instance only post and we can think of this post as resources but when we will have also users maybe we'll have interactions maybe we'll have groups or anything else that we could have on a social network so you can imagine it or you can see that we can actually group those type of resources or this type of end points into groupings of endpoints that in a certain way belong together and this means that we can also replicate this type of model where grouping different endpoints that belong together in their dedicated classes it would be a good approach to actually have a sustainable and maintainable and scalable minimal API project so just writing everything here will not really help at all so in order to do that because there is one other thing the other thing is that whenever you have kind of like such a new grouping of endpoints it means that anytime you add a new one you should make sure that you come here and kind of like call the method that would register all the handlers from that specific grouping of endpoints now this would also be a little bit cumbersome so what I want to propose you is show you a way that uses a little bit of reflection but that is really powerful because when you set up your project this way you just have to write that thing once and then no matter how many such groupings of endpoints you add to your application they will automatically be added and mapped as route handlers and you can directly use them so to set everything up we first of all will need an interface for that so it means that we'll go over here and we'll create a new folder and we'll call this folder abstractions so let's call this abstractions and in this folder abstractions I will create an interface that I will call let's say what is your class and then I'll choose interface and I choose to use the naming of endpoint definition and I see endpoint definition so I endpoint definition I guess it's correct the idea is that it means that kind of like we have groupings that Define route and that's why I see endpoint definition because it refers to a certain endpoint like the post but it defines different routes for it so I call this endpoint definition however you don't have to stick to this naming you can group or name uh your classes that will group the different route handles the way you want you can use modules you can use some other type of naming so that's really not important at all now the only thing is that we will or the only thing that will Define in this interface is here a method that will be register endpoints and it will pass in the web application because on the app is the place where we actually register the endpoint and now the next thing that we can do here is add another folder in the minimal API so we'll go to add new folder and we'll call this folder endpoint definitions and here in this endpoint definitions you can think about this folder like similar to the folder called controllers in regular asp.net core projects so here we'll add a new class and we'll call this class a post endpoint definition because it's an endpoint definition that refers to my post so that's the way that I prefer name things here and here I would say that I inherit I endpoint definition so endpoint definition it should be like this I guess but maybe I have mistyped something uh generate uh I end point definition okay let me go back to the interface because maybe I have something wrong here so I end point yeah of course of course I did this wrong so let's rename this I endpoint definition something like this okay I want to rename also the interface and everything around that but also it's still not okay so let's let's just rename it once again because this e should be capitalized and yeah right now aren't they it didn't do this here so let's make it like that and then let's go back to our post endpoint definition and here and I endpoint definition using minimal API abstraction is cool so that's exactly what we want to use and then of course we just need to implement this interface so we will have this method here now the only thing is that or or the thing that we could do here is right now we could even go to the program.cs and make sure that we'll take everything that we have here will take really all these routes because all these routes are kind of like definitions for my post endpoint and we'll just cut everything from here and we'll move it to this post endpoint definition in the register endpoints method and here we have done kind of like this uh cool and let's see if everything works of course probably will have to to import here some bunch of fusings that have so that everything is okay it will be for queries I guess we need to add uh for posts and uh I guess that uh that should be kind of like it for now we just have moved everything away from there but also this sweet name I don't like let's let's make it like this and here I have now all my endpoints definitions cool and then the final step to actually reorganizing and make sure that whenever we add a new class that implements this I endpoint definition it will automatically be added or that those endpoints will automatically be mapped so that we don't have to manually map everything or go to the program.cs and call methods to to map this for each different endpoint definition here is the part where I said it kind of like we could do something very very nice and neat and use just a little bit of reflection to get things started so let's go back to this other class which is the minimal API extensions and we will do just that so I have here a code sample or a code snippet that I that I also use and let me I don't know maybe let's just bring this to another line uh so that it becomes more clear and I will explain what we'll do here but actually it looks maybe a little bit complicated because it's reflection but in the end it's really really easy to understand so what we do here is that of course what we want to do is we want to scan our assembly where we have the program class which would be essentially the minimal API assembly and we want to scan this assembly for types that are assignable or that implement the I endpoint definition in the endpoint definition interface but and this is very important we want to also make sure that we want to only get types that are not abstract and that are not interfaces because if we don't add this it would mean that when we do this for each it will also take into consideration the interface and the interface is something that we surely cannot create an in distance of so that's why this condition here is very important so that those types should not be abstract classes and should not be interfaces now when we have uh well filter those types so we have seen okay how many types do we have right now in our assembly that implement the eye end point definition interface is that we make a projection and for each of them we create an instance so we virtually create an instance of that specific class now being the fact that the class contains basically uh or implements this endpoint definition interface it will also means that that it it implements sorry the register endpoints method which is kind of like cool but the only thing that we have to do afterwards is because by reflection it doesn't really know exactly that it is an endpoint definition so we cast it to the interface itself so what we end up having is that we'll have an innumerable of objects because they are instantiated because we use the activator to create instances that implement the I endpoint definition interface and this in turns means that we can Loop or iterate through that innumerable and for each of the objects that we have there we just hit this register endpoints and automatically it will be registered so this means that right now once we have this method when if I go here to endpoint definitions and I create a new class like for instance I don't know comments or endpoint definitions and if I implement this uh I am pre-definition interface I don't have to do anything it will automatically also or those endpoints will automatically also be mapped because of this forage and that's a really powerful way to keep everything very very very clean now the only thing of course that we need to do here is we need on this app to call or how did we call that method let me go back here because I really just forgot I'm pretty old so register endpoint definition so let me go back here to this program and yeah just use this extension method and everything should be cool now prove you that this actually works we can just run the application and then head over to postman and try again at least a bunch of endpoints too just make sure that everything still works correctly because at this point as we have just moved all the definitions or all the endpoint mappings into a different file if one is working it means that all others will still be working very very fine so let's have this get all posts and let's hit the send request and I would expect a 200 okay result that will return me a collection of two posts like it did previously and indeed so everything works but right now basically if we go back here we can see that our program.cs class gets much much cleaner and having this type of structure into your application actually means that no matter how many services you will still add no matter how many endpoint definitions you will have this file or this class will always remain like that it will never change anymore so and it is pretty straightforward so like like what you're doing here you're registering Services we have an extension methods for that uh then we build the application we use the https redirection and then we register endpoint definitions and that's it so everything else happens from this point on into each of the endpoint definition files so this is a very very good way to keep your minimal API structure very very clean and easy to understand and from my point of view also very well organized however we are not ready yet there are some things that things that I don't like about how the code is here and I would for sure not have or write such code in a production radio app or for a customer and the first thing that that actually I see here that kind of like is a problem and it was a problem when I was typing all these endpoints is that we have a lot of or well apart from our endpoint but from the route it's very repetitive so for each endpoint we have this kind of like base or slash API slash posts now one very important thing that we have in.net 7 minimal API and that we did not have in dot net 6 minimally API is the ability to actually create a route groups and the way this works we can say here VAR uh posts equals app dot map group and when we say this map group what we can do here is actually specify that we want to map a group or API slash posts and this will become the fact of our base URL address let's say or all the endpoints that we have and what this allows us to do here is that in this case we can just first of all replace here this with post and in that case we don't need all the stuff anymore the only the thing that we need or the only thing that we need is the ID if we go here once again we can replace this with posts because in this map group we then register or map a post in that case in this case actually this is like this because it's on API post directly and it would be okay now the get when we get the list is exactly the same so we can just replace here with posts and it should still work of course we need them to replace this and just say that that's the base URL for the group this is what we actually want to map and then for the put it's exactly the same so we can simply use this post and then we can just remove everything from here and just keep the ID because that it ID is what's different in this route right now and the map delete we can do exactly the same so instead of app we'd have post with the map delete so or weak and we can go get rid of this kind of stuff here cool so if I run the application and if I go then over to postman I would expect right now to have the exact same result but right now the route mappings are a little bit more clear and easier to write taking advantage of this map group feature that we have in.7 minimal apis and once again that we did not have previously in the.net6 minimal API and from my point of view this is a very neat and useful Improvement on what the dotnet6 minimally API actually was but I am still not happy with the code that I have here why I'm not happy because right now okay we have optimized it a lot but still we have this lambdas and all the code that we have is placed into lambdas and what I would like to have is in the place or the place where I Define my route I want to have it very very succinct and clearly what are the current routes for that certain endpoint definitions so this I don't really have to scroll through all the stuff here actually see what my routes are so this would mean that what I would like to do is to extract actually all this logic that we have into this Lambda Expressions into own methods and then use those methods here basically as route Handler and that would kind of like simplify a lot that the way that my code would look like and uh yeah that's kind of like very very easy to achieve so let's start with the first one here which is uh yeah let's let's copy this code which is the map get and here we actually get by ID so the first one is the get by ID cool so let me just also make sure that okay where is the class where does the class and here does it end quote so what we'll do here we'll uh have here a private and in this private method we uh it should then basically return an i result so that's exactly what we want to do but as it could be as it will be async it should return a task of I result once again we are using these results and I result it basically is implemented by result very similar to what the I action result is once again in asp.net core so we'll have here I result this would be a task of our result and the name of this method would be I'll get a post by edit now the one thing that we have to make sure is that we kind of like keep uh the parameters that we have in the method so we need the mediator and we need the int ID so let's let's use that so I mediator uh cool so this is the mediator let's call it the mediator and then int ID it should be like that and here we can just paste the code that we previously had in the Lambda uh of course we need to make this async cool so now that's async everything is okay however there is one other thing that I would like to optimize and I briefly told you about that at a certain point when we were creating endpoints is that one way that we can return results is just by results okay but the other way is the typed result typed results okay and of course I have a typo here so this is why it's not working and between results and type results there is a big difference because as the name of this class implies the results that we kind of like create right now with the post is a type result of okay of post and the thing is that previously this was not available in.net6 and it made testing minimal API pretty uh pretty complicated because every time when you made a request for instance you needed to test okay is the response 200 then serialize the body to Json or to an object and see exactly if that object is assignable to a post and and things similar to that and that was kind of like a little bit cumbersome but with the type results it's easier to test because you can then make just a request in HTTP client and expect a type result of okay of post and everything should be run or it should be fine so the key learning here is that in order to make your app application or your minimal API easier to test just make sure that you always return typed results and not only results that would be a very very important part cool but now we have this method so it means that we can go back up here and what we can do in this method we can just keep the name and everything but we can actually remove everything from here and we can just get a post by ID you just specify the name of the method and since this is a delegate dot Net 7 will make sure that it will inject uh here in this method all the things that we need like the mediator and the route param that we have actually for that one and once again that's actually very very easy or it it it's more readable than previously so what we can do here once again of course is we can apply exactly the same principle a private async uh task of I result I should once again type correctly and this is the create post method and in this create post method I guess we need the mediator so we need the I mediator and let's give it also a name after this and we need a post which is a post so this is what we need there and then the things that we can add here is once again created post and instead of returning results we will return typed results like we did earlier and we've created it route and this one should be okay uh okay what is the problem right here uh created post with ID argument cannot convert from type Anonymous type into an INT of string ah okay so the problem here is with the type results is that um yeah now probably here in this case uh we just need to use till the results and then everything should be okay now if we go back to this uh create that we have it means that we can get the read actually of everything that we have here and instead replace it with this create post and yeah now everything should be fine okay then we can do exactly the same thing also for this uh other map get in in this case we just need the mediator so let's go here and let's create a private async task of a result and uh what was a get uh all posts so that's what we can do here and uh yeah here we just need the mediator my mediator mediator and then we can just move here the text and also change this to a typed result and it should be okay now what we can do is of course get into this method and once again we can virtually delete everything here and to get all posts cool so now we have this one now we have this update and for the update we need the mediator we need the post and we need the ID so we'll keep this in mind let's just also create this method the private async task of I result okay and update post cool so what did we say that we actually need here actually we'll just copy this and paste this over and we'll know so first of all we need the I mediator then we'll need the post and then we'll need the int ID and we are going to go with this method right now so we can just come back here well this one and just delete everything and replace it with update post it could be this one so that's okay and last but not least we have this delete and in this delete we need the image mediator and the ID so let's also go here and create a private async task of I result like we did earlier and here delete post so here but here we'll also change this to be a typed results like we did also previously and here we have the delete post so I mediator that's what we need the mediator and we need the int ID and then we can just paste everything here change these results into typed results and then basically we can go over here and once again we can delete everything from here and replace it with the okay but we still need the parenthesis so delete Outpost that would be the one with which we replaced and as you see right now basically when I go into my method I can even uh well make this or optimize the space between and what this refactoring allows me to do is that right now when I come to an endpoint definition class I can already see okay these are my endpoints because I'm not interested I just want to have an overview okay those are the end points then if I want to go for the implementation of of the method and the logic and how it's implemented we can well simply jump over and and go to it but we have one place in which we can see virtually all the endpoints that we have mapped for that specific endpoint definition and that already is very very important now let's prove that this still works by running the application and trying to make another request but I am fairly confident that things will still work just fine and that we will not have any problems so let me just hit the send uh okay so it seems that we had a problem okay what did we do here API slash post error okay something with the connection is not okay uh let me check is the application running so yeah it seems that the application is running correctly uh let me I don't know maybe just try again maybe the application was not started yet when when I ran the request so yeah hopefully this time it will work but I think I think it should work because every time it's the first time that it makes a database it takes longer but we prove that it works so we have actually refactored right now our endpoint definition so that it looks first of all easier to read it is easier to maintain because you can go in each method and just update that specific method you can have a look at all the mapped routes just in a single place you don't have to scroll around and we have improved by using type results so that we have made right now our endpoints easier to test which is actually very very very great however there are still two more things that I would like to include here in this full course on the dot Net 7 minimal API with clean architecture EF core repository pattern secure as in mediator and that is okay we have some endpoints for instance for the create create and for the update where we kind of like get a post from the body now one thing that we want to do is we want to do model validation and I really want to go into this topic because in asp.net core in the in the controllers like the regular apis we have that model State and we can easily decorate for instance our post with different attributes in in if we specify exactly some rules for validation and then we can simply use the model state to check if the model state is valid or not now one thing with the minimally API is that it doesn't have a model state so this means that we will have to handle the validation by our by ourselves now that's not necessarily too complicated because we could even use libraries like fluent validation to achieve that but in this video I just want to show you what's the best way to actually perform validation in.net 7 minimal apis with a very very minimum validation that we will add ourselves but of course you can extend that we use fluent validation and then well create your validators or your apps and validators to Define exactly what and how do you want to validate now one other thing that's important and that was not previously there in.net6 and for for me that's why the dot S6 minimal apis were a no-go is that it didn't have or it yeah didn't have support or filters and that's a big problem because usually when you think about validation you think about filters filters in asp.net core as a concept is just a way to perform some actions right before an action is executed and right after the action is executed that's why filters are useful and that's why validation is usually done in the filter now this means that in.net7 I said we have now support for filters now the filters in.net 7 minimal API are surely different than the filters that we have in regular asp.net core applications because in asp.net core like the regular controller based approach we have different types of filter filters we did that kind of like have a different purpose we have a filter pipeline that also depends by type by the way that you register it in dot Net 7 minimal API it's well a little bit more straightforward for now and the filters are actually called endpoint filters now what I would like to do here is Sim simply add a new validator as a filter as a DOT Net 7 minimal API filter so for this one I'll add a new folder and I'll call this folder filters and in this filters folder I will add a new class that I will call a post validation filter so post validation filter that's how I call this one now to make your class being a filter the only thing that you would need to do is to inherit I endpoint sorry Implement not inherit because it's an interface so I endpoint filter and of course when we want to inherit an interface well that means that we will probably also have to implement some bunch of stuff and that's actually the implementation of a filter in what we have here so we have here a value task with a invoke async that that's the method and I will I have a code snippet here that I have already prepared so I'll just use it and we will go through this once again so of course this need to be made also async because that's well of course an async thing now uh good what we can do here and here the post uh content um what's the problem with this in indicates okay uh there is no argument given that corresponds to the required parameter value of string is null or empty okay cool uh we'll we'll just look look into that now the problem here is or what we actually want to do here is first of all we want to well validate our post now in the minimal API what it happens is that when a request comes in um basically in this endpoint filter invocation context we have a collection of arguments like the arguments that were passed in either throughout params or to the body all the arguments uh actually that are passed into our route anger including services that are injected from the dependency injection container and this is why when we want to get a certain argument because we want to only validate the post we need actually to say okay we want to validate the second agreement and as opposed so this is why this is a generic but then it's also important to go to the definition the here is the place why I said it's important that here when we have this create the post should be at the second place and for uh the update it should always be at the second place because then in our filter what we can do here is we can say get arguments of one as all collections it's zero index so it means that the first element will be or the first argument will be on index 0 and the second argument will be on index one and this in turn means that uh yeah in this case we will always be sure that we'll always validate this filter or this uh or the post now we have created the filter now the only other thing that we need to do is kind of like say to the specific endpoint that hey for this endpoint also please use this filter to actually validate our post so if we go back to this post endpoint definition uh here first of all we need to go to this create post not here but where we did the mapping so this is the create post and like we had this width name which was a metadata info information for that specific route what we can do here is you can say require require endpoint how how was that method called let me let me just check it was it was required but it don't uh don't recall exactly uh and endpoint filter not required sorry uh so yes it was add endpoint filter and this is a generic method in which we say that hey we want to add a filter which is of type post validation filter and uh yeah that means that we have added our filter to this specific method and of course we can then just take this from here and what we can do we can just paste it or copy this of course and also paste this for the update because this is also the point where we actually want to validate something cool and let's now prove that this actually works but what we want to do let's go back to the filter because I think I want to do this a little bit differently uh okay so it away task from result the idea is that if if the content is null or empty so if we provide an empty string in the body we just return a task which is a result bed request so we just created bed request cool uh in that case let me let me just validate here so uh yeah let me just run this applications and let me show you how that filter works so remember we can validate or we can see if everything okay we have some Builders okay now we don't want to run where are my build errors uh okay cool I don't see any Builders let me rebuild the solution in this case and then uh pinpoint exactly where the problems are okay so the problem was actually that the content was uh well a nullable string and then we should have all this string is null or empty on the post content so sorry for that uh okay cool so now we have a working project once again and we can just run it and test once again the validator out and let let me just wait a little bit until it starts and want to emphasize once again that the validation is done on the create and here on the update so we can just use the create and here in the create body in order for the filter to actually kick in and return a bad request we can just pass in an empty string so in this case when we run this request we see that here okay we received this uh 400 bed request host is not valid so exactly what we have actually written here uh in this result we can maybe just I don't know move this return so that it's visible so it's exactly what we have uh we have defined here is what it was actually returned so we have proved that actually the validation Works in this case now before we wrap up is there actually one other thing that I would like to show you because uh one thing that I can really here reproduce very very easy is a scenario where we get exceptions because surely in your minimal API you will also get exceptions uh that happens now if I have changed here this argument from one to zero I know that the first argument is the imediator and it is not the post and I would expect that in this case actually when I run this application and when I try to create for instance a new post I would expect here to receive an exception and actually well as it happens when exceptions are thrown that's really not beautiful at all so let's do this and let's wait for the request and indeed we see that we have here this invalid cost exception because we wanted to cast the mediator enter to a post and of course that was not possible so we got an exception the question then arises what do we do with exceptions in minimal apis now just a short reminder when we talk about regular apis where we have controllers there are literally two ways to catch these exceptions globally there is one way to use exception filters for that and it is the other way to use like a middleware and I have created a video specifically on that topic showing exactly what is the difference between when you use exceptional filters and when you use middleware however here in minimal API we don't really have an exception filter so it means that kind of like we need to use a middleware for that now where to put this middleware of course like we do in regular asp.net core applications here is where we actually configure our middleware Pipeline and the exception filter should actually be the first in the pipeline because it would also be the last through which actually a request goes through when when something happens and I will paste here this code for a very very basic middleware which what is all it's basic but it is a global exception handling middleware like app.tuse and we have the context in the next what we do here is we put this aways next in a try block it means that if anywhere down the line it will throw an error on an exception we will catch it here and once we catch it well we set the status code to 500 and we write the response will which will actually then create these 500 response and send it back to the consumer and this kind of like changes dramatically because right now no exception will be thrown but the consumer will be kind of like notified in a very regular and standard rest way that hey we had an exception and here if I run the application again and if I will do the exact same post request once again that I know for sure it will kind of like cause trouble and create an exception condition I will see that the result will be totally different because in this case uh let's just wait for a bit we just have a 500 internal server error and an error occurred uh either way in this case actually it's not really a server error because oh it is a server error in the end because we didn't map Things correctly so it's not a clutter so we are okay to send the 500 request but you notice the difference now instead of just throwing an exception and uh well then the reception was then received by Postman and Postman knows how to potentially handle that but you can assume if there is a Content that consumes this and it receives kind of like hit there's an exception well it it wouldn't really know exactly what to do with that because it would expect something in Json format or at least something that's formatted in a certain way and that's what we actually want to do with this Global exception ending middleware that we have here of course you could even format or write as a Json here maybe you can create an error object and you can create a tostring method that kind of like creates a Json representation of that object and here in this right async that you can then call that object with the two string and it will result in a nicely formatted Json but for the purpose of this kind of like short tutorial or actually it was not that short but it was in depth because it covered really all the areas that that you need to be careful about and you that you need to be aware about of when you start to really work on on a real project with the donor 7 minimal API so um yeah the idea is that we have right now okay I guess we have covered everything that I wanted to uh do here and before we wrap up I just want to make a brief summary of what we have discussed during uh this uh uh this short course uh because we have started really from the very beginning we wanted to create a Net 7 minimal API with clean architecture with exact folder structure with database using Entity framework core also using the repository pattern and also using cqrs with mediator so that was the purpose of what we wanted to do and therefore we started right from scratch when we have modeled our project structure according to the clean architectural principles and we have defined our layers like domain the data access the application layer and the minimal API itself then we went one step further we have defined our domain model which was a very simple post then we have implemented the data access layer we have seen how well we implemented we how we Implement repository pattern and how everything fits fits together when we work with this kind of like minimal API because when you are creating migrations and updating the database uh the uh well starting project or the startup project for the migrations and and for application that the database is the minimal API project so we have seen how we have set that up and then we went over to implement the application layer where we have used kind of like a secure s approach using the mediator Library so we have um we have defined our applications in or we we have subdivided actions that might occur in our applications between queries and commands and for each of them we have dedicated handlers that would handle that specific query or that specific comment and then for the most part of this course we have concentrated on the minimal API itself and we have actually taken a very very I would say pedagogical approach we have started from what everybody does usually in demos and in documentations we have placed everything in our program.ts and then we have step-by-step uh or we have looked step by step for ways in a way which can improve our code base so that in the end we want it to end up with kind of like a template that you can take when you create a minimal API project that's clean that's readable that's easier to test and that's also easy to maintain and we have refactored all that we have written towards this kind of goal and scope to make it to make everything as clean as possible and for that we have used filters for validation we have implemented also middleware we have implemented extension methods this kind of like register Services we have implemented an extension method on the web application that automatically scans the entire assembly or endpoint definitions and automatically registers the routes so that we have to set up set this up only once we install the project and then no matter how many classes you add that inherit from that I endpoint definition interface everything will be automatically added as a route when the application starts up so that's kind of like a very very powerful thing and I would strongly advise you to actually do that now probably you will hear a lot of people say hey but you're using reflection and reflection is uh or causes a performance problems and yes that's true but you only run that reflection code once and startup so when you're starting up the application to be honest I am not really concerned about the performance of course if it would take 10 minutes for the application to start up then I would be considered even one minute but it still starts up very very fast and you only have to perform this once so the downside is that there is a performance cost but the upside of this is that hey everything will be automatically or all your routes we will be automatically mapped no matter how many eye endpoint definitions you have and this kind of like brings a very very uh well healthy plus to the equation and I would therefore recommend to go for this approach because it's really really powerful this being said thank you very much for the patience that you had for watching this entire video I hope it was helpful for you and I really hope that it provides you with a good foundation and kind of like a template and structure whenever you need to create a new minimal API project that's kind of like a template to use for your real applications for customers for interviews you can just look to that and you can customize it it further with all endpoint definitions that we need with filters that you might need to add also and with with other middleware if you might need to to add middleware and a lot of other commands and queries and handlers but that's really you have the baseline from this here or from from this point on you can really build upon this and how do I create any type of application that you might need with this.net server mini minimal API if you think that this content was useful for you don't be shy and hit the thumbs up button for this video also subscribe to the code wrinkles Channel if you didn't do this already and also hit the notification Bell to make sure that you are notified whenever we have new content here on this channel and also if you think that there might be other people that would find this content useful don't be shy and share the content with your peers with your colleagues with whoever you think it might be interested maybe at work in your social media on forms wherever you think there is somebody that might find this useful please do that and probably that that person would be thankful to you this being said once again thank you very much for watching and until the next time I wish you the very best
Info
Channel: Codewrinkles
Views: 22,238
Rating: undefined out of 5
Keywords: .net, .net 7, .net core, .net maui, asp net core web api, asp.net core, clean architecture, clean architecture c#, dotnet, dotnet 7, ef core 7, mediatr, minimal api, minimal api c#, minimal api dotnet 6, minimal api dotnet 7
Id: RRrsFE6OXAQ
Channel Id: undefined
Length: 125min 19sec (7519 seconds)
Published: Sun Nov 20 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.