An Opinionated, Maintainable REST API Architecture for ASP.NET Core - Spencer Schneidenbach

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everybody welcome my name is Spencer shinai de Bock and I'm here to tell you about a maintainable opinionated and since I'm opinionated right way to build applications using ASP net core specifically REST API or API is in general can I get a quick show of hands how many people are using asp net core today okay a few of you good good how many are using I'm going to use this a lot old asp net web api like i don't think it's although I think it's awesome cool a lot of you okay so what I'm telling you today I mean it has core in the title but everything I'm telling you today applies just as well to asp net web api there's a couple of things you need to change other than that it's pretty much mostly the same so if you have any questions about anything please reach out to me I have my contact information on on the slides so oh and action item Bach on Twitter so good way to get a hold of me first thing that I have to say is that of my co-host Heather and I are doing a interview show with some of the top speakers here at NBC and it's coming July 15 so keep an eye out for it we've got some really cool things they teach you something in five minutes it's awesome okay housekeeping thing number two is I already talked about PubCon right awesome everything that you see everything that I'm telling you you can add you can add me on Twitter at night and box you know I wouldn't you know try to spell it it's just take a picture right or you can go to rest Knives net the precursor to this talk which is which is restful api design which was given to them you see that recording is available I highly recommend you watch it if you are looking to create your own REST API and everything that I'm talking about all the resources everything at rest is met I don't get paid to say that even though it's my website there's no ads so I'm not making any money it's really to help you all the resources rest at tonight's net okay awesome so let's set the stage a little bit right so you your boss comes to you you're a web developer and a lot of asp net developers in here which is awesome a love HP net and he says he or she says we need a new single page application right where we need a new REST API you did something that our customers want to be able to consume they want to get data out of our API they want to create data inside of our application we want to create a system where they can integrate really well I'm an integration specialist so that's like really important to me so you say awesome okay I can do that I'm a discerning developer I know exactly what I need to do I'm going to fire up asp net core right or old asp net web api right hold because I still use asp net web api out of curiosity how many web forms people here this is my favorite question to ask because inevitably there's like a couple of hands that like creep up silently but they don't want to admit it but look I'm a web forms developer - okay awesome right and I saw another guy over here right so web forms you probably can't do this stuff but still cool to use right maybe not but anyways I always like to ask that question so old-old is relative again all of this applicable to asp net web api right so you're going to choose one of those two things and you want to go from zero to make magic happen as quickly as possible right like you want to see something on the page your angular developer your react developer or you want to see a record go to the database so you want to make something that gets you from zero to make magic happen as quickly as possible right you want to do something right and the first thing you think of is scaffolding scaffolding scaffolding is great right it's the promise is that it's amazing and that it's productivity and awesomeness and in a lot of ways it is scaffolding is cool scaffolding is magic right it's kind of the promise right and it's very easy to do right let's take a tour let's take a tour of a scaffold and application of a scaffolded asp net web api application in this case it's core all in Visual Studio right because Microsoft provides all this great tooling to you might as well use it right but first let's introduce our friend the employee object let's say your system that has a representation for employees right you have an ID you have a first and last name you notice are decorated with the required attributes because they're required data and you've got a date of birth and a date of hire and a social security number wait e8 where am i what what the heck is a social security number I made this mistake in London I had to slide up and I was like oh I don't know that they know what a social security number is I need to make that mistake again so I'm in Norway so I'm going to talk about the birth number or the national ID number right or that word right so you the bottom line is is that it's the employee object is an object that is part of a payroll system right something like that a lot of people deal with payroll a lot of people deal with employee records in some way kind of contain sensitive data in this case we'll just say SSN but national ID number birth number whatever you want to call it it's sensitive data so you need to treat it you need to treat it differently right you need to treat it in a way that you need to encrypt it right all that kind of stuff so I'm setting the stage a little bit right and you're the developer you love Visual Studio and you love visual Studios tooling and you love to get stuff done so what do you do you go to file new project and you choose asp net core and then maybe you add any framework right this is opinionated talk I like entity framework you may use something different and that's ok you may use web api plus something complete you may use n hibernate and that's ok right all of these things so these are the this is the core of your application right you've got a something that processes requests something that talks to a database you go to file new project and this is kind of what you're looking at now for those of you there was about I think about half of people have looked at core there's a few things that are different so first thing and probably the best change I can think of is now none of the static files in the code files and the views and the controller's the CS files right there used to be in Web API they're all intermingled they're all together and then asp net iis just serves them up differently based on the file type right and in this case now core is probably the number one improvement maybe not the number one improvement one of the one of the number one improvements was moving that all to a WW route so all of your static data now goes and is served out of that folder right so if you've got scripts that's get a script folder inside of the path you directory you have to do some kind of process to move those files over to the WWE directory before they're served so that's awesome other than that there's really not much changed you've still got you've still got controllers models views those folders stay the same and oops and you have this is a little different so web.config is a little bit some of its functionality has been replaced with the app settings JSON file right there's a couple other things including the startup dot CS the startups at CES is a lot different now used to how many people are familiar with global dot is ax and you don't have to play in that phone okay most most asp net developers are anybody intermingle it with startup that CS they have both existing in their web api or MVC project okay a few of you so start-up CS has really taken the place of what global dot s ax really did which is just like handle the startup of the application right you're handling the startup of the application and you're defining in this file this is a little different from startup that CS that you use a web api you're defining all the services that are used inside of your application right so this is all the stuff that core needs to run and nothing is put there by default when you new up a Web API or an MVC project the handlers for asp net web api and MVC they run through when you make a request they run through well maybe this needs to handle it no need to pass it on to this need to pass it on to this right it goes through a chain of processes and it'll always run every time in the Nate and asp net core you don't have that you don't need that so you actually opt in to everything you don't even serve static files by default you have to add in you have to opt it you have to opt those things in right you get to pick and choose what you want but most people will start with just add MVC right and that will give them all of their this particular line will give them all of the services that their MVC application needs to run it'll make their controllers work it'll put in routing all of that good stuff it makes those things available to the asp net core pipeline right ok and then you notice a little bit different there is an ad DB context which is an extension method on your app builder ok and that is simply says I want to make an application DV context available to my request pipeline as well so that way if a certain controller or service is requesting that it will get it will get instantiated with this connection string and injected right into that controller and we'll see an example of that in just a second but first you notice of course we've got our employee object our employee object is now inside of our project folder so we've added our employee model there's all that code and the first number right and then you're like okay well now I've connected entity framework so just as an example right because the tooling likes entity framework so now we've got our model now we're going to add our controller and we're going to scaffold it's going to be awesome right so you're going to right click on your controller we're going to go to add your controllers folder you're going to right click on it you're going to say add controller and there it is right at the top ready and then you're going to have a list of choices and your list of choices is going to include we're going to select the bottom one right so you can do empty readwrite actions you can just do an empty controller you can do one that serves up views an MVC controller in this case we're going to do an API so we're going to select the bottom one and we're going to say hey we're going to use entity framework with it and we want you to we want to scaffold up all the readwrite actions for this controller so then you get a nice handy little dialog box that says I pick your employee click your pick your application DB context you're using and then say the name of the controller right it's that simple and then you'll sit you'll hit OK and end it in asp net and visual studio actually will go through and scaffold up those controllers it will make one for you and then you've got yourself a wild employees controller it has appeared in your solution and it's awesome right because it's got a bunch of stuff so let's look at the first thing the first thing that's a little different about it from when you did this in web api how many people use scaffolding in the past a fair number of you I'd say ok less of you than I thought but still a good number so generate it's just code Jen right it's generating all this awesome code for you right get you started quickly so it's got an employee's controller right off the top there decorated with something like that says produces right and it says that by default request to this produce application jason which is different how many people when they're using web api had to go through and the default serializer was XML and they had to remove it or make sure that when jason they wanted to serve jason right it's default by a default request I see a few hands go up you don't have to do that now you can just decorate the controller and say request of this will prove produced application Jason then you say I've got a default route this is a little bit different if you use route attribute if you use routing attributes in Web API this is a little different now it's just called route and you say API slash employees okay so all the requests from there on we'll look at if you go to API slash employees that it'll route that request naturally if it's a get request for the rather to the get to post request it'll route it to the post and so on and then this is the biggest change which is thou the the application dbcontext is now injected into your controller by the asp net pipeline remember that inside of our startup CS we injected that we said we want to make this service available when you're running MVC services we want to make this service available to all the other services that need it so that's great so essentially when you make this request you'll automatically get a new employees controller and it will instantiate it with this application dbcontext already ready to go cool and that's different from web api scaffolding where you it would just do up its own application dbcontext which is not as good which is bad right because then it's creating its own things we want to tell it what we want we'll get to that in a minute then we do get requests right we've get something where we just define something where we say I want to get all employees for this controller for all the employees for this particular organization okay that's a good start for like maybe if you know a couple hundred employees that'd be good maybe there's page there maybe there's a paging option that you want to add in we're not going to talk about that but you look at that you're like okay that's a good start that's a good way to does a good way to speak in and then of course just the single get where you make a request by ID you say maybe you say does this person have access to this yes or no okay then I'm going to go ahead and send that back if it's an invalid request for whatever reason if it's a get request then I'll return bad request and give them a nice little message okay so that's the get request so then we get to the put request which actually changes employees now I'm going to talk through this a little bit because this one's a little bit weird to me this doesn't make a lot of sense what you end up with is of course if Model state is invalid return bad request that's a good start okay but notice that what we're putting into this request right if you make a put request to this specific ID and then you say I'm going to give it this employee data you notice that you're using the same entity as you are you're using the same model your entity model as the one for the request well that could be good or bad depending on your requirements right and we'll get to that in a little bit well then you say I'm going to try it and then it's and then if then it becomes you get this little check on line 10 ish where you say if the ID that I passed in is different from the employee ID that I've given in my request then return bed requesting you're like okay why do I have to give that twice okay whatever you know I'll just do that that's fine and then it says I'm going to modify it said it's modified so entity framework knows to update it and then it saves it to the database it is updated okay alright that's not so bad otherwise we'll return will reduce if there's a problem doing that we will return a different error message depending on the problem right and then of course we get to the post request which is a little bit simpler because it's just creating an employee right then you're just adding it to the context and you're validating it adding it to the context and then you're saving it to the database cool right and then of course the delete you may do something where you're deleting it straight from the database you may have a soft deleted kind of situation where you just want to mark it as delete it inside the database but you don't actually want to get rid of it by default web API gives it you don't just straight removes it from the database and that's okay right that could be okay depending on your need so that's a scaffolded controller so just with a few clicks you've gotten something that's great right it's awesome its productivity it's amazing but I am here to tell you that in many cases as your application grows scaffolding is a lie scaffolding is a lie perpetrated on you by Microsoft and yes I'm a Microsoft MVP and yes I can say that but scaffolding is a lie scaffolding is something that is great to get started right but in long term it has some problems because your controller first of all is a one-man army your controller is now responsible for getting the routing requests kind of the asp net router system handles that but then once it gets to the controller the controller's like oh this is them this is the method I should use right so it's responsible for doing that is good controllers should do that it should define where the requests should go but then it's also validating it and then it's also running the service right it's updating the database it's deleting from the database we're adding to the database or even getting right at doing everything and then it's returned to the request which is okay because that's what a controller is really good at but your controller in this case is doing everything and that's a problem because there's no separation of concerns inside of your application inside of your controller specifically your controller is literally responsible now maybe that's okay for five controllers but five hundred we run into some problems what we're going to do I'm going to describe to you ways around that and it's going to be a refactoring exercise right we're just going to take you through how I would make it how I would change this controller to make it better okay because in the end the controller should only route the request and return data that's what it's good at the controller is good at saying hey this thing knows how to do this thing so I'm going to send this request to this thing so it can do what it does best which is whatever thing it's requesting okay and then I'll return the data return whatever data that it asked me for another big problem and this is probably maybe I don't know this is a big problem to me your entity also is your request right let's think about that let's think about that birth number right you may you may not want that to be something that you want to be updated maybe that's a business rule and a little bit it will be a business rule but in this case you just don't need it you don't wanted them have to have the ability to update it so you just toss it you don't you want to toss it away right you don't want that to be something that you wanted them to update your your consumers are then able to I don't know over post right they can add they can change properties that they're not supposed to change if they're aware of them things like that right problems so let's break it up let's break it apart into all the little pieces and parse that that is necessary right so we're going to talk about something called command query responsibility segregation okay and this is a great pattern for basically separating the requests from the from the services that run those requests I'm going to take you through how you might break that thing down the bottom line is that we're going to move the validation the running of our service and the requests we're going to remove those all somewhere else right so we're going to move those out of the controller the entity is no longer going to be responsible for being the request object okay and the and there's a few reasons why why is that good reliability right so a reusability and maybe let's say that you have services that you define in another assembly and then Web API is just aware of them right and then it uses those services to route requests and do stuff but you may not be able to predict where you know HTTP is you know where we do the majority of our work for our what if we're a web developer but you don't know maybe somebody else wants to use that service somewhere down the rot line you may not be able to predict that so then you get to be able to reuse your code right next thing separation of concerns okay so now everything is really good at doing the one thing that it's asked to do the controller right now is kind of good at doing the few things that it's been asked to do but by and large it's really really only good for one or two things and that's really where it should where all of its functionality should stay and then easier testing right so it becomes much easier to test these once you have these individual components right you can write unit tests for each of those different things and end up being able to control and predict where things are going to fail or if things code changes somewhere down the line then it will fail you know it'll fail faster that way right unit test so let's start with the request let's break this baby apart right so same thing same employee object that we have and you notice that we have our validation inside of an employee object more on that a little later so again the entity is being used for requests that's a bad thing right because again for lots of reasons over posting reasons you may not want them you may they may not be aware of properties on there you may not make them aware of properties on that object that you don't want to send back and then when they do a put request they're not aware of them either so they may void out those requests in my other rest awk I talked about where I do exactly that i under post data I under put data to a certain endpoint and I didn't know that doing so would break their application but it literally broke them they didn't have any validation which is a terrible rule anyways but because I didn't send all the requisite properties that I was supposed to do without that I was supposed to send in this request it ended up making the applicant put me application in an illegal state like a state where we just wouldn't run right there's a lot of reasons so we want to break that apart and then we want to we want to separate the responsibility for model validation from the model right something else is probably best suited to validate and make sure that that model is good okay so let's refactor let's start by separating the model from the entity right so we've got our employee object but we've got our business rule that says that when we make a put request we don't want to be able we want to be able to have that employee be able to made with a put request or and with the birth number with a post request right when there's on creation but we don't want that to happen when they update it now this is a really simple rule and you can write around this a little bit right but as we know when we make requests like these these rules can get infinitely complicated right these rules can be a the complexity of these can go far and beyond just this one little example it's hard to code for that so let's not let's just make it very simple so let's create something where we actually have something that actually creates the object for us so we create an employee create request right so this is what what we're doing here is we're breaking things down into one request one request class or definition one request definition per per request that we're making so we're going to end up making a update request as well and you notice that I'm just missing that property straight up I'm not actually setting that property at all it's not something that a SP net becomes aware of even if they post a birth number it doesn't matter because it's because it's not it's deserialize it's just an object that c-sharp is aware of but birth number gets thrown away right and then we can do a delete request where we simply just say hey we just want the ID of the request and then something on the other end can handle that okay so another thing is is those required attributes are little clunky to validate especially if you're not using ASP net right at some point you may end up using something other than asp net and that becomes very clunky to validate its this is an example of the clunkiness right so this is an example I pulled off a Stack Overflow two links at the bottom of this slide somewhere and essentially they've just done some attribute routing but they needed some special behaviors right they needed some special things that they needed to do they needed additional validation but you notice that well okay first you got to do up a validation result in you oh you implement this cool I validate able object then that's a that's an interface that defines a validate method and you essentially return them validation results and if they're invalid and you know is it one or more in validation result inside of that set denotes an invalid object so they try to validate that property and you're like okay I'm going to validate this property and then I'm going to new up a validation context whatever that is right I thought I was already getting one but apparently I'm a new one up and then I'm going to pass in null and you're like I look at this and you're like is that good is that bad like what am i passing it maybe I maybe maybe it needs that thing I'm supposed to avoid no reference exception and you're telling me I need to put null into this it's very confusing the API is extremely confusing and it's just not nice so opinion here's the opinion warning I have a library that I use called fluent validation and fluid out validation is game-changing well it's life-changing it's maybe not as life-changing it like having a kid but it's certainly more life-changing than this right it's more life-changing than this this should just make you one that to not be a developer so fluent validations are really awesome library and essentially what you do is you define a single class so let's say let's take our employee request first so we'll just boil it down to just the first and last name to keep it simple so what you do is you just it's a separate class becomes responsible for validating that this class is valid so we want to have isolate that validation functionality so what we do is we create what's called an abstract validator right or we've create a class that's an employee create validator and inherit from abstract validator that's a class inside affluent validation and then we give it the type of the thing that we're validating so that way we get strongly typed miss as opposed to that new prop one stuff so I don't even know right we don't have to worry about all that because now we just construct our object and then we say here's a rule and here's the rule for first name I don't want it to be empty and empty is great because the required attributes are kind of kind of funny in that you there's actually if you pass it an empty string that's a vow that's technically valid right unless you said there's a required attribute as a property set allow empty strings you can set false and you can cover that but you don't want to do that that's a lot of typing right forget about it you want to just say I want to make sure that this thing is not empty and not empty means not default value not know and in this case not an empty string so it gives you it it's better defined to the purpose right you want a first or last name attached to that employee it better define to the purpose of that employee because the first and last name should never be empty strings either so that's awesome and they have a ton of methods that allow you to build different validation functionality you could say it has to be equal to this you could say it has to be a range of numbers right there's a lot of stuff built in personally I discovered it by simply gotten looking at intellisense and seeing all the different rules that are available and you can do some pretty complex behaviors right some pretty complex validation it's better way better than that mess that we saw so then you say I want to say that first and last name were required and I want to give a special error message and this is a part where resource strings really come in handy because if you have to do English or Norwegian because I'm in Norway right you have to do English in Norwegian you can use resource strings and you can reuse those strings and it becomes very nice cool so now we've separated our validation behavior from our request our request is no longer responsible for also defining its own validation and for a simple thing like first and last name where you just need to say I just want it required and I don't want empty strings that's fine but validation behavior can get pretty extensive right all right we'll talk about that in a second but first we've got to saut we got to mention that testability right so now we can test our validator separately from our request right we don't have to create a separate request new it up with a bunch of stuff have create some validation context where you're passing in 40,000 nulls and you don't know what that does that's good or bad you can just say I'm going to do up the validation request I'm going to validate this object and then I'm going to make sure that the validation error that the validation errors have something that has a first name and a last name right and so that way when Johnny junior developer or Jane junior developer comes in and deletes that line of code now you have a test to back that up right because tests aren't really written for just today to validate that things work today there are also things that work tomorrow for things that work tomorrow right you want to guarantee that behavior works tomorrow as well so how so your validators can have some complex behaviors you may need to talk to a database to make sure that for your delete request that something exists so you may need to add that to your maiden to add that to your constructor and then you say I'm going to pass in an application dbcontext and I just want to make sure that it exists first and then you get a cool API where you can kind of write it in English or you know whatever language you're writing it in right or you could say like I'm going to define a method called existing database and then I call a method fluent validator has a method called must must exist in database it becomes very readable becomes fluid it's a fluid API that's kind of it's one of its design goals we've separated our request model from our entity and we've separated our validation from our request model so awesome we've created two totally different things so we've done some good work already refactoring good the next let's get to the meat of it right so we've done very important steps but now we need to extract those services and for this thing we're going to talk about the post request for this particular example we're going to talk about the post request right so it's creating it's doing all this work is creating this object and of course it's getting the entity straight from the request which is just crazy if you don't want that right so now we're going to make it so that we can do some we can save it to the database but the controller doesn't know how the controller doesn't really care right so next opinion ding-ding-ding the warning sign you know something it's like a big flashing red sign opinion opinion alert right so I use a library called mediator how many people use auto member lots of people use autumn after autumn a purse auto magical okay look it up if you haven't but autumn a pers written by a guy named Jimmy Bogart he's speaking at this conference and Jimmy also wrote a library's way lesser-known but in many ways just as useful and for different things though it's called mediator and it essentially is kind of like a message processing request inside of a process right so mediator is really good at separating requests from handlers request handlers right so request comes in the request handler handles it okay and mediator is really good at that so let's look with that let's take a look at what that looks like let's keep refactoring our application so first things first we have our employee create request just as we did before with all the validations separated out which is awesome that's good we do our employee create request and then you notice that this little line right here we've changed it we've added we've implemented an interface called I request and I request as a special interface it doesn't really do anything it doesn't define behavior or properties it's really a marker that's what it is it says hey this object represents a request I request as part of the mediator library so this object represents a request and then you give it the return type when you create the employee so one thing you need to know probably that you might want to return to the client the ID of the thing that you've created right because it doesn't get to choose its ID it's an auto incrementing database so you just give it the ID back so that's all we're asking we're saying hey this request is this is a request and it's going to return an ID in the response right so that's thing one we've changed our request so now we've defined we're going to do step two and we're going to basically do the same thing that we did pulling out the validation pulling out the request but we're going to do it with the service now we're going to handle the post request we're going to save that thing to the database we're going to create that new thing and we're going to add that to the service so we're going to define a service with that implements this I request handler okay and you give it the request and then they work the type of the request and then the type of the response okay what you're going to end up with is this little method here called handle because it actually does implement some behavior and handle takes in the request and you notice that it's return type is int just like this right just like the thing that we want to return we want to return the ID of the object common question is well what about async await there's actually an eye a sink request an eye space Inc request Handler and then handle becomes the task event that what it ends up returning okay so a sink away totally totally available to mediator as well so then we end up with our request that creates our employee we set the properties from that request and then we save it to the date we add it to our context if you're using entity framework which we are and then we save it to the database and then we return the new employee ID and everybody's happy right well I mean you happy if you're writing plumbing code right nobody writes likes to write properties like this objects as we know can get huge I mean that's just Lewis especially we're using legacy applications we've got a god object and it has 100 properties nobody wants to type then you go to nimble text or some kind of text editor that allows you to like copy paste and just a mess right and we don't have time for that there's no time for that we don't have time for that we don't want to write plumbing code that's not where we're here for we're here to sing so we're going to do we're going to use Auto mapper right so inside of the service we're going to inject Auto mapper and Auto mappers a way to map objects from one map objects together so our employee create request in this case can be mapped such that all of its data can be transferred to a new copy of an employee entity right we're going to do this just to keep things easy an auto map or does all the wiring for you is the properties names are the same then Auto mapper knows what to do and it sets all those properties for you and it's great so you inject in your mapper you can add it as part of your as in your services in your in your service CS sorry your startup CS and add it in there and add it as a service that's available inside of your asp net application right and then you can do something like this which is a lot night so you can create an employee then you've just mapped it straight from that right so save time so that way we're not doing the whole property set thing which you don't want to do and I don't want to do it scaffold apparently scaffolding didn't want to do either so that's awesome so now we've ended up with a service but where does it get validated the service so I like to implement a pattern where I create a common service based class and I say all of the requests all of the validators that go in for this request inject those straight in right if we inject those straight into the constructor and we say I'm going to go ahead and validate all these I'm going to run through each of those and I'm going to check that of its valid and if it's not I'm going to return some validation results or throw about in this kit usually I throw a validation exception right I don't have the code for this because it couldn't all fit on the slide if you go to rest on eyes net I link to a great Jimmy Bogart article that shows you exactly how to do it takes it step-by-step okay and we're going to do all of our validation and we're going to register those validation in validators inside of start-up CS right so it's going to be made available to that service to use which is awesome cool so now it's validating itself so I create one base class that that validates the request that I inherit from that with all of my services right and so I've created something that reusable and repeatable in a very lightweight way I just want to make sure that my services are about my request are validated and before you even another common question that I get is you know multiple validators why would you just not have one you may have a validator that's really good about validating some very complex things about your object that boiled down to maybe touching one or two properties I don't know I can't predict that you may want to break up your validators is the bottom line so you don't want to assume that there's just one so we add multiples because if you do assume there's just one then a lot of dependency injection libraries will just return the first that it has and you may not want that so we do multiples awesome so it becomes independently testable so now this service is really good at doing its one thing so we're going to test an assert that this be that this service is really doing this really good one thing and as of course it's reusable which we described earlier we may want to use it outside of an asp net core application right we may want to do that we don't know why but we may want to it's more important that it be separate though that's the most important takeaway so let's put it all together dependency injection handles dependencies right so the thing that where we configured all of our services we added MVC to the pipeline we added the application dbcontext and now we've added in Auto mapper and a bunch of other services and a bunch of other validators to our pipeline right we made those things all available so that's what it does best it says this thing is dependent on this thing so we're going to create that thing with all the things that it needs that like enough things in that sentence we're going to have mediator do the request we're going to define requests to mediator and then we're going to define responses through mediator right or in this case handlers the mediator is doing that it's really good at defining requests and handlers and then controller will do what it does best which is take an HTTP request do something with it send it off to somebody who knows what to do with it and then return the data that's what the controller's good at that's what the controllers for it's like a traffic I like to think of a controller as a traffic cop it just says okay you need to go here you need to go here you need to go here okay the bottom line is the next thing is the that dependency injection was never baked into asp net web api if you're using web api looks like if you're using web api you can add it in of course you know you can add dependency injection in very well but it wasn't made a first-class citizen until core so but i would recommend using a better dependency injection container I personally like Auto fact I see lots of people use ninja I see some use structure map it doesn't really matter do something that just makes your life easier in this way I kind of use it like Auto mapper and I'll show you how Auto mapper or Auto fact will allow you will automatically scan your assemblies you can say hey scan this assembly for all of these interfaces and just automatically add them to the dependency injection pipeline because you could depart the you can define them one of the time say I'm going to add this service than this service but when you get to 100 services in 100 validators that becomes pretty heavy so you'd probably you may not want to do that you may might be like me and just want to get stuff done so what I love to do with get stuff done so we're going to do something like this we're going to change our startup dot CS file a little bit we're going to say hey I want you to create this content to create this container builder which is an auto fact thing that is built into Auto fact I'm going to new that up and then I'm going to say hey I want to scan every service assembly because you may have your services in a separate assembly you may not depend on you but you want to do right you may have you want to scan that assembly and you just say I want to register all the types as implemented interfaces right and this just goes through every single type and every time it has an interface it says okay this is an eye validator so when I validator that validates employee create request so when it's creating so when it's something is asking for it gets injected in right you can also filter this down because you may not want that behavior you may want to filter only the things that implement I request or I abstract abstract validator or or ice async request handler or something like that okay so do something save yourself some time don't do them one at a time use Auto fact use something use something awesome right so then the thing that you need to do is make sure that mediator so you'll need to register mediator as part of this part of this whole process mediator is a thing that is actually an object that is created it actually handles that request we're going to add it to that service pipeline and then we're going to add it to the controller so that the controller knows who to ask for things right knows that oh the mediator is the the god of all requests and knows I don't know I just present the request that the altar of the mediator and then the mediator blesses me with a response to that request it takes that it takes that create post request or create employee request and routes it to wherever it needs to go and out comes an ID and who knows if it actually created something I don't care because I'm the controller I don't really want to know right so we add that in of course we would add in our application DB context here as well still I just left it out for brevity and then finally our controller we've refactored so let's let's break this down we refactored the request we've taken the request separated it we've taken the validator separated it we've taken our service and separated it from the controller so now the controller's not left doing much which is great this is the thing the controller should do right so we say hey mediator handle this request again I don't know what it's doing I just know that you're going to return an ID and that's awesome because I'm going to assume that it went to a database and happy flowers are growing and everything is good everything is good and great right I handle that request and then we say hey creative action right we want to return it can to control is good at saying hey httprequest here's a response right here's how you get that new employee that you just created right and that's good and then if we have any validation you can say hey I'm going to throw an exception I'm going to catch this validation exception and say if there's any validation errors thrown I'm going to go ahead and return bad requests and then I'm going to give it something with model state which this is just an extension method that I define myself if you want it you can ask me for it I don't have a post anywhere I will do that though in the next couple of days on rest is net but essentially it just creates a model state and just adds all those error messages to that model state okay so let's wrap up with a few tips okay my thing is creating repeatable patterns I like to create repeatable patterns for success so part of my job is I own a consultancy and I have a junior developer and giving her patterns to repeat write something because she's definitely into a development so I give her patterns I say hey do this formula and follow this through and this becomes really powerful when you're training junior developers because now you don't have to say you know scaffold up 400 applicant 400 controllers for these different objects right you can just say hey I want you to do this methodically and we want to build software right especially if it's an API that somebody else is consuming I've consumed tons of bad api's which in my other talk you can hear me tell all the horror stories but imagine how powerful that becomes right you say hey let's do this one step at a time let's break this down we're going to define our request what is our thing going to do right what is it what is the data that our things needs to do what data does it need then I'm going to say hey let's validate that request I'm going to give you a list of business rules and based on that ask fluent validation to say hey ensure that this string is empty ensure that this number is between 0 and 100 right and possibilities are endless there then you say define a service and then you say hey now we have our request we validated it let's define let's inherit from this base service that we've created that automatically hooks all the validation up and then you just implement the handle interface and then save it to the database delete it from the database you know whatever right becomes very powerful because you've broken it up into finite steps and you're testing all along the way to make sure that your validator works properly that your service is going to work properly right because we all do unit testing right right right they're better more complete example Jimmy Bogaerts blog right here on this link go ahead I'll wait you click on it okay well we're going to get this slide you can click on that link and it's right there in the links that I provide as well okay write test for everything I can't emphasize this enough now yeah and I have no exceptions to that rule I just think you should write test for everything and a lot of people think that this slows them down but it doesn't and there's plenty of people who give good talks on why testing is important so I'm not going to beat it into your head I will just say that it becomes the thing that is powerful for testing for me is that it becomes a spec it becomes the way your software should behave it becomes and not only does it become the spec it guarantees that spec stays the same so that when Jimmy jr. developer comes in and deletes that line of code the whole build comes crashing down because you failed that one unit test and by the way that functionality was really critical and you have some consumers of your API that really suck like me sitting under not sending enough you know data to that put request right they didn't validate it I didn't send enough data everybody screwed up so avoid that I can tell you by the way that the particular API that I used that had this problem I talked to them it was a SP net web api and no it wasn't backed by a single unit test so they had a lot of breaking changes between their behavior I think that the my favorite example of that was in my other talk day I said they said oh yeah we changed some stuff that happens under these couple of endpoints nothing really changed from a request standpoint you know just see let us know if you have any problems we just changed them underpinnings and we said oh okay let's you know I want to run our suite of unit integration tests to guarantee that that stuff still works as advertised and they said actually we're deploying in one hour because we need it right away and they're like well and then you're stuck saying well I don't know you we have about 500 customers that depend on this API working properly what are you going to tell do I want to tell them why don't you have the conversation with them in case your API gets screwed up right and by the way nothing broke that time but then other times where things broke so right test for everything I like to keep versions separate this is another kind of opinionated thing but if you're creating a REST API you are probably going to version it right and I talked about all the strategies behind that and my other talk but the bottom line is is that you may have services that where the employee only takes a certain number of properties or maybe rename properties from the next version of that where you add in some behavior right so I like to separate those into separate versions so I have a separate assembly right where I keep all those things I say here's my separate version I'm going to say version 1 version 1 services scan that assembly put on all those services and then the version 2 of my API has lots of API 2 version you're doing a REST API or any kind of API at some point you'll probably version it as well and then you can keep it in two separate assemblies and then you can just add those to the pipeline and that way everything's kept nice and separate and then you have another separate test project as well right keeps everything nice and neatly organized which is great so other bad sides to this approach I think there are right so it may be unnecessary complexity if you're spinning up a website they say actually we just want a newsletter we just want to be able to send a newsletter right and you're trying to get something done quickly you really just want you don't care about that it's not business critical day to say we just want a place where the text box in a button right that may be unnecessary to do something like this to implement this huge amount of patterns right I mean because the bottom line is we don't want to spend a lot of time doing that newsletter where there's two controllers and all they're serving a static static data except in this one instance where it does a post request and you're like I don't know I don't care because like I mean you can do all that stuff right apply all those patterns but you may be just spinning your wheels you may be doing something that doesn't have a lot of value and your boss probably will forget about it next week anyways and then of course there's a there's a bigger learning curve and I'd say this with this one is arguable arguable because there's kind of a little bit of a learning curve in breaking down how the controller handles things at the surface it seems pretty straightforward right it's talking to a database it's you know deserializing a request is routing that request and saving it doing some stuff right so the cognitive load as your controllers get more complicated the cognitive load can increase right so this I mean you have to learn some more libraries that's the bottom line you do but once you get to that point things become simpler your code becomes simpler everything kind of simplifies because well everything is doing the one thing that it's really good at doing it's really good at being a request it's really good at being a validator right that kind of stuff I find that this is best for medium to large-sized application so if you know your application is going to grow you said well the in the newsletter endpoint isn't enough we need 14 more endpoints to handle some very specific customer behavior you may go back and say well I may refactor or may apply this pattern right because I want to I want to have some strong guarantees about about this is a customer facing thing or even some internal facing thing that's business critical and I want to have some strong guarantees as it's going to function the way that I've said it's going to function so I'm going to go through and apply this pattern and you'll and you'll be rewarded for that right be rewarded intrinsically because you'll know it will work in the most part and then a reliability right you don't have to worry about controller being the single source of failure now it's the course entity framework are not talking to the database maybe the database servers down the true source of failure but it's kind of masked right because the controller is the one responsible for knowing all that information right you throw an exception and then you have to go and say well it threw an exception at employee controller line 23 so then you dig into the code maybe you're logging isn't good you dig into the code you look at line 23 you're like oh that's the part words save it to the database I should maybe start there right whereas you might be able to start a lot simple you're like oh and and it failed at the validator for XY and Z right makes things a little less obscure and it makes your code makes your code cleaner and that's a good thing this is really I don't have anything else to say except all these resources everything that I links to all this stuff resinize net take a picture look it up later again I I answer questions all the time about this kind of thing people reach out to me all the time having to give free advice so please reach out to me on Twitter and usually I'm going to I'm going to save questions at the end in case anybody wants to go down and join the awesome party that's about to occur so any questions you just come up to me on the stage and I'll be happy to talk you through your particular problem but the bottom line is is thank you so much for being here again please reach out to me go to my website reach out to me again I don't make any money on this no ads I just want to help you if you have any questions please feel free to reach out I'm at schnide and Bach SAS at me comm is my email address just go to my website you find all that so thank you so much again my name is Spencer strike it's been a pleasure talking to you thank you [Applause]
Info
Channel: NDC Conferences
Views: 10,496
Rating: 4.9560437 out of 5
Keywords: NDC, NDC Oslo, Spencer Schneidenbach, .NET, Web
Id: CH9VEeV-zok
Channel Id: undefined
Length: 49min 28sec (2968 seconds)
Published: Wed Jul 05 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.