NestJS, GraphQL & TypeORM Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone my name is Anson we're back with a brand new video in this video I'm going to show you all how to set up a graphql server in nestjs so this by no means is a beginner tutorial there is already implication that you have worked with graphql you have some experience with graphql this tutorial is mainly for people who want to actually set up graphql with nestjs they want to use graphql in their nestjs project okay so obviously you need to one know how to use nestjs and two know at least some basics of graphql okay so if you don't know graphql though I do encourage you to read up upon it uh look up the tutorial explaining what graph is and then come back to this video but I will do my best to kind of like hold all of your hands to just kind of like guide you through how to set everything up so even if you don't know graphql I'll still try to like baby you all through this whole process okay in a way that doesn't make it seem you know too boring for those who already know graph already I'll try my best anyways let's go ahead and get started so I'm not really going to go in depth with what graphql is I'll just mention that graphql itself is a very powerful query tool that you can use um instead of using the traditional rest API you can use graphql to query your data which is basically the alternative to making a get request to get data and then you can use what's called a mutation to create data update data stuff like that okay and one of the biggest problems that graph solves is over fetching and under fetching because there are times where you will interact with a rest API that gives you a bunch of unnecessary Fields a bunch of unnecessary data that is taking up uh you know bandwidth when it's being sent back to the client and sometimes just unnecessary to have all that data because you're probably never going to use it so with graphql you can basically Target specifically what fields that you want okay and you'll get exactly what you ask for so if you don't ask for you know certain fields that are part of that API call then you won't get it okay or in this case the graphql query it also prevents you from under fetching because you can literally just set up a query that gets you the bare minimum data that you need for your application so that's one of the reasons why many people use graphic it also solves um the issue with relational um data at the kind of like the client level whereas if you're using a database like SQL SQL would solve the relational issue at database level so graph does in a way allow your data to be relational cuz it's kind of like combining a bunch of Records Al together into one single response that's being sent back to the client and all of those uh data that is being resolved back to the client all has relation with each other okay it's kind of like a graph where it all kind of connects to each other in some way so hopefully that brief literal explanation makes sense okay let's go ahead and set up a project and then install some of our dependencies so obviously first make sure you have the nest CLI installed I'm assuming all of you that are watching already have experience with Nest so I'm not going to go over that it's going to go into my terminal my windows Powershell and I'm going to use the nest CLI I'm going to type Nest new and I'm going to type graphql tutorial nestjs this will generate a project for me I'm going to use npm as my package manager and while it is setting up uh the scaffold of our project I will mention One Thing by default uh many of you should no this by now if not I will explain again nestjs does use express underneath the hood or it's built on top of Express and it uses Express for many of its features okay but if you want to use fastify which is an alternative web framework than Express you actually can use fastify but if you do use fastify though and if you want to follow along while also using fastify uh you have to install different dependencies okay so right over here on the top I am going to to be installing these four dependencies right over here nestjs graphql nestjs Apollo Apollo server and then graphql if you're using fasty and you're also wanting to use the Apollo uh server as well then you'll reference this line right over here uh all of these dependencies are the same except for this one right over here as Integrations SL fasty let me zoom out a little bit okay but if you're using fasty and you don't want to use Apollo but you want to use uh a different driver it's called mercurious you can just install these dependencies uh I'm going to like I said I'm going to be using Express and Apollo so I'm going to install these dependencies but it shouldn't really make much a difference in terms of writing the code okay so I'm going to go ahead and copy uh this Command right over here going to go back to my windows Parell I'm going to CD into that project that I just created so graphql tutorial nestjs and all of the code that I'm going to be writing in this video will be in a GitHub repository and I'll leave a link in the description to that GitHub repository so that way you all can use it as a reference so I'm in my project folder right now I'm going to go ahead and paste that npm command to install all of my dependencies okay so once again that's just these four so let's just do that okay cool so it's done let's open up visual studio code okay awesome now what I'm going to just quickly do is I'm going to remove a couple files that we're not going to need at all so I'm going to remove um this spec file the controller file the default ones that have been generated I'm going to remove the service file because we're not going to need this one going to go inside app. module. TS and remove these two Imports and then remove these two references because they no longer are relevant and that's pretty much it so let's go ahead and run our project just to make sure everything is good so we'll type npm Run start colon Dev so run the dev script cool all right so we have uh our graphql packages installed let me just verify that yes I have Apollo server um I have all of our packages installed great that's wonderful so now what I need to do is I need to go into app. module. TS the root module and I'm going to go ahead and import graphql module from the nestjs graphql package at nestjs SLG graphql I'm going to go inside the Imports array and I'm going to go ahead and reference graphql module just like that and call the static for root method okay and this is what initializes the actual graph kill module itself we do want to pass in a couple of options I will type annotate this for root method call to Apollo config or Apollo driver config okay this ensures that I don't provide properties that are for a different driver in this case we're using Apollo so I'm just going to make sure you don't have to do this part but I think it's a good idea to do it anyways so now what I'm going to do is I'm going to set the driver to Apollo driver and this is going to be a class uh that actually is imported from at nestjs Apollo so since I already have that up top over here I'll just add Apollo driver just like that okay cool so we're done with this part um now what we can do is let's look at our console and you'll see our logs we are going to get an error and that's totally normal because we don't have any root query right now we need to actually create a query in order to do that though we first need to actually create a type and then we need to create a resolver class and inside the resolver class is where we will Define our queries which they're just really just functions now one more thing that I did forget to mention is that in nestjs there's two ways that you can actually use graphql there's the code first approach and and then there is the schema first approach um there's pros and cons with both it's really up to you I'll show you an example that the documentation has with code first versus uh schema first so if you look at this example with code first um where is it right [Music] here trying to find it uh right over okay so if you look at code first you'll see that instead of using the traditional schema definition language you're actually going to be using the language that you're using to write your application in this case it's typescript so we're going to be using typescript classes to create our models or our graph K types so you can see over here in this example they have an author class and they use decorators to annotate each field as a graphql field okay and we'll go through all this when we create our own types so don't worry this is what it looks like with a code first approach and this is really good if you want to make sure you keep your whole code base consistent with you know just typescript you don't want any graphql language at all so again it's up to you on what you choose to do if you want to do a schema first approach you can use the graphql schema definition language to create your type so that's this is what it would look like like whichever one you choose in the end nestjs will take care of generating the appropriate um definition so if you're using schema first it will generate appropriate interfaces for use that you can use it to type annotate your stuff your properties if you're using Code first it will generate uh those classes into uh a graphql schema into one file and I'll show you that later as well okay so hopefully all that makes sense but in this video we will be using Code first approach okay so let's go ahead and go into our source folder I'll create a new folder and I'll call this graphql and I'll go and ahead and create another folder inside graphql and I'll call this models now I'll create a file and I'm going to create a simple model I'll call this user okay and now what I'll do is I'll create a class I'll call this class user and in order to tell graphql that this is a type we need to use this object type decorator okay now we need to import that so let's import that from at njsg graphql just like that this is a decorator okay and then now we also need to Define our field so so it's very similar to how you would Define Fields normally in a class so I'm going to Define an ID field which will be a number and then what I need to do to tell graphql that this is an actual field because like I said Nest is going to translate this class into an actual graph C schema in its own file so we need to make sure we are using these uh decorators appropriately so I'm going to use this field decorator and we need to import that from the same package nestjs SLG graphql and then I'm going to invoke this function cuz the decorators are really just functions okay now one thing that I will also do is create another field so I'll use the field decorator and I'll call this field username and this will be of type string and then I'll do another one display name I'll call it string as well okay pretty straightforward okay nothing too complicated now one thing that I do want to mention is that when you're working with numeric values you need to make sure you actually pass in this type function inside the field uh decorator so it'll look something like this type and then it'll return this int we have to import this from nestjs graphql so this will sure that this ID is actually an in you can actually do float as well there's also another import called float okay but you need to make sure you do this because um if you don't by default it'll actually it it will generate the schema and It'll recognize this ID as a float in this case IDs typically are are integers not floats so you want to make sure you take care of that and you only really need to do this when you have the number type you don't have to do this if it's a string or a booing so I don't have to do this for username or display name okay I'll show you another example of how we can handle nullable values for our Fields as well so I'll leave username as a non- knowable field but for display name I want that to be knowable so I'll use I'll add the question mark operator right in front of this property so that will just tell typescript that this is nullable but it won't tell graph C that it is tell graphql that it is nullable we have to pass in this object and then set nullable to true so when the actual schema gets generated from this typescript class you'll see that the appropriate um operators are applied the appropriate symbols are applied to the fields and you'll see that once we actually have the file generated right now it won't be generated because we actually need to use this graph Q model in order to use it we first need to create a resolver okay so hopefully that hopefully so far everything makes sense we simply just created a class we defined our fields and we used the object type decorator to annotate our user class to say hey this is going to be whoops this is going to be a uh a graphql type and then we use the field decorator to annotate our class Fields saying that this is going to be a field inside our graphql type that's all it is okay let's go ahead and close this out and what we'll do is we'll create another folder inside graphql I'll call this resolvers I'll create a file and I'll call this user resolver CS now inside this user resolver file we're actually going to create our user resolver class now I know I didn't mention what a resolver is and again this is where you need to make sure you know your graphql terminology but for those of you who are not too familiar with resolvers basically a resolver is a way for you to actually interact with your data the primary goal of the resolver is to actually uh populate your data with the correct fields or populate your Fields with the correct data sorry I got it the other way around populate your Fields with the correct data and it'll go ahead and get that data from either the database or an external API or whatever data source it needs to get it from okay that's what the resolver is responsible for in sjs though it is done a little bit differently because we do need to create the resolver class and inside that class we're going to actually Define our queries uh using methods and the query decorator so I I'll show you how that works so first let's go ahead and create this user resolver class whoops we're going to need to use the resolver decorator and before I do anything else let me import resolver and that should come from the graphql package my uh Imports are messed up right now but I need to restart my typescript server but I'm not going to do that it's okay so what I'll do next is inside this user resolver class what we want to Simply do is just create a method that is going to be responsible for querying our data so if I want want to get the user itself then what I would do first is I would create a method and I would call this get user you can call it whatever you want I'm going to call a get user and this method can return whatever you want but typically it should return the data corresponding to the resolver in this case it's going to be a user okay so for now I'll just create a or I'll just return a fake user so ID of one username Anson display name name is optional but I will provide a display name and we'll call it Anon the developer we'll set that value to be Anon the developer to tell graphql that this get user method is a query I need to use the query decorator and this is not coming from nestjs common but from graphql the graphql package okay NJ is graph package and what we're going to do is inside the deck Creator argument we're going to pass in this optional function and we're going to say returns and we're going to specify what it returns we actually have to do this so that way graph K knows what it's supposed to return all right so now graphql will know that this query will return a user okay so we'll leave it like this for now let's go ahead and uh take our user resolver we need to go inside and register the user resolver inside the app. module. Cs file so if you've used njs before which again you probably already did if you're watching this video you'll know how to register providers okay those are pretty much like Services repositories for you know your data layer things like that so all we do is we just need to take this user resolver and pass it in as a provider and I'm just going to import that into my apom module. ts file just like that and now the last thing that we do need to do though is we need to we need to specify this Autos schema file property inside uh the graph c. for root uh options object and this is because we need to actually have our autogenerated schema file so this is just going to be a string and it's going to be a relative path to where you want that file to be generated I'll have it generated inside the Source folder and I'll just call this file graphql or schema. gql and now see how a new file was created whoops uh let me actually I'm going to delete this okay but now you see I have the schema. gql file and you'll see that has some comments up here this file was automatically generated and you'll see that we have our type and then we have the type query and then it has our us it has our get user query very very straightforward and again if you've used graph before in a schema first approach where you actually used the schema definition language to write out your types and write out your queries this is what it would look like okay all right cool so now one thing that I do want to do since our uh project now should not have any errors because we we do have one root query okay so no error so far let's actually go into the browser and let's take a look at our app so let me move this over here okay so right now my nestjs API is running on Local Host Port 3000 but what I want to show you all is the graph C playground which I'm sure some of you might be familiar with but for those of you who are not this is just basically a UI that you can access to test out your graphql server but you access it by just simply going to your local host and then the port and then slash graphql and now you'll see this whole user interface right over here and this was actually from a tutorial that I cre that I created earlier we just ignore this part and then you can see if I click on schema I can now see the type I see the user I see all of its fields and then I see uh the root query and then I see see get user query over there okay uh so that's pretty cool and you'll you'll see how um these exclamation marks which you should know by now that basically means the value is non knowable remember how I set display name to be nullable notice how there's no exclamation mark next to it next to the string keyword because it means that display name is nullable okay hopefully that makes sense and you can see how that reflects okay let's go ahead execute this get user query CU we have data that's being returned let's grab the ID theay name and the username and let's click play and you can see now I get my data and that's good it's working great okay so hopefully that is pretty straightforward there you go and that is how you can set up graphql in your project we're not done yet of course but I just wanted to mention that it's just that easy you first uh register the graphql module okay then you create a graph C type okay then you create the resolver and then you register the resolver by passing it as a provider inside the app. module. Cs okay very very very straightforward so now let's go ahead and play around with our resolver with our queries because we can be creative with this now so what I'll do is is I'll change this query to be get user by ID I'll create a mock array of users so let me create a new folder I'll call thisor MOX call this mock users. TS and let go back to so let me paste that user over here I'll do the same same thing two more times let's change the ID up a little bit and let's change the names let's do [Music] Jack and let's do Peter or it should be lowercase Peter all right so we have some users so uh so now that we have our query get user by ID uh I'm going to show you how we can actually pass arguments in our query okay so it's actually very easy all you need to do is just use this args decorator and this is going to imported from the nestjs graphql package and then you're going to give your argument a name you can call it whatever you want but this is this decorator is for the translation when it uh translates into graphql it'll reflect the name based on this okay and then now just give your argument name whatever you want this is just for the ACT ual code itself it doesn't have to be the same but I'm just going to keep it the same for now and remember the ID is actually supposed to be a number so let's do that let's set this to be a number okay so we have ID set to a number and now if I go into the schema file you'll see right over here that something interesting happens well yes first we can see that the argument is there but you see how it's a float okay and this is this is actually really related to the issue that I told you about earlier where if you don't have this type function set it's going to uh pretty much like cast it to a float and that's not what we want okay so in this situation what we can do inside uh The args Decorator as a second argument I can pass in an object and I can pass in this type property and then this is going to be a function that just pretty much will return the same thing that that we had returned right over here int so let's import that from nestjs graphql and return that okay now if I go back to my schema. graphql file you'll see now it's actually an INT and not a float so that's very important all right so now uh whatever whatever ID that we were to pass in from the graph client okay is what will be the value of this ID in the code so for example if I go back into the graph playground we no longer have this get user query anymore if I click play it's not going to work if I look at the schema you'll see that now we have this get user by ID okay and of course the ID is not nullable so let's actually fix this up to change let's change it to get user by ID and since we're passing an argument we need to use parenthesis so I'm going to go ahead and specify the argument name so ID and then colon and I can pass in whatever value I want that's a number so I'll pass in one obviously this doesn't do anything right now because we need to change our logic to actually reflect searching for the user by typy since we don't have a database set up yet what I'll do is I will go ahead and import the mock users constant or the mock users array from the mock users file and then I'll just simply callind and I'll search for um the user by its ID so you can pretend like this is a database call or a call to the database I'm going to go ahead and pass in this predicate function and so this element is going to be the user itself the current element in the in the array and we want to check the ID the user. ID is equal to ID so if this is true it'll return the user however there's a situation where it might not even return the user at all it might be null so let's first do this let's click on play let's change it to two you can see I get a different user if I let's say if I put five you see how we get an error so we need to make sure we are handling this accordingly because this query itself right now is defined as it returns a non-nullable value if you look at the schema you see how it has this exclamation mark next to this return type user that means it's returning a non-null value but it could return a null value though so what we need to do is we need to adjust this so right over up top here we can pass in query options and then I can set nullable to be true okay and now watch this if I leave the query alone CU I don't have a user with id5 if I click play you'll see that this query returns null okay pretty pretty simple hopefully that makes sense now one more thing I do also want to mention before we move on is you can actually change the name of the query CU right now this itself is the method name whatever the method name is is going to be mapped into the actual schema file itself okay and that's actually going to be what what query name you're going to need to use if you want to change the name but keep the method name alone inside the same object the query options object uh right over here whoops the query options object you can pass in this name and you can name this whatever you want you can call a user by ID for example and then if you look right over here in the schema it's now changed to user by ID okay same thing in the file it now shows user by ID and you'll notice how the exclamation mark is no longer at the end of this user type because it's nullable now okay so hopefully that makes sense I'm going to remove this name property though because I I just want to leave it like this all right so let's move on let's create another query let's do a very simple one where we return an array of users so we do need to provide this function right over here where we're indicating the return type so we'll do this um because we are returning an array of users this time we need to actually use square bracket and then pass in the type that we're returning like this not like this where you have user and then square bracket it's square bracket user just like that that will tell graphql that you are returning an array of users for this query okay so now I'm going to create a method I'll call this get users with an S at the end and then what I'll do is I will simply I don't think I'll need any arguments for now but later on if you want to get creative you want to add Arguments for filtering you can um but we'll leave it alone for now so I'll do return mock users just like that okay and now if I go into scheme of file you'll see I have this get users um query right over here and it returns an right of users and it is non-nullable so now if I were to I think I might be able to use two queries over here so let's do get users and let's only grab the username only okay so now you can see that I have my get users query being executed over here as well as my get user byid query okay so let's remove this and let's grab other values as well let's get the ID and now I can see that I have an array of all of my users from our code UN code database our fake database okay so it's it's that easy it's that easy all right hopefully that that makes sense but now let's get into some more complicated stuff so right now we have a type of user that has three values that are scalar values we have number string okay we we could have bleen but we don't we'll leave that alone for now but these are scalar values okay kind of like primitive values but what if we had a field that was a non-scalar value what if it was like an object like uh maybe maybe the user class might have um a settings field and that settings field is of a custom type that we can create like a user setting type okay and that user setting type will represent the settings for the user maybe you're building some kind of application and you want the user to be able to configure their settings for let's say mobile text notifications things like that how would we ensure that we are resolving the user settings value for the corresponding user okay and this is where it kind of starts to get tricky because it depends on the kind of database you're using because if you're using a non-relational database like mongodb then this is actually perfect because you don't have to even worry about relational stuff at all at the database level you can let graphql take care of it for you because what graphql will do is it will call a resolver function to resolve the corresponding field to ensure sure that you are getting the correct data that is relevant to that user so it kind of takes non-relational data and then it joins it all together to make it relational if that makes sense okay so I'll show you an example so what we'll do first is we'll go ahead and create another type so I'll go into my models and I'll create a new file my models folder and I'll create a new file I'll call this user setting TS and uh we're just going to do the same exact thing we're going to import um the same decorators so let's do this export class user setting and then we will use the object type decorator okay let's just import that whoops from sjs fql okay uh I have my object type so let's go ahead and Define a couple of fields so we'll start off with um we we do need a user ID though because keep keep in mind that in in this situation um we do have a onetoone relationship between the user and the user setting because for example a user should only have one user setting and the user setting should only belong to one user okay and furthermore user the user record can exist without the user setting but the user setting cannot exist without the user so let me let me let me repeat that again so the user record in your database can exist without a user setting record associated with it okay because maybe the user does not have a user setting they can still use the application but they just don't have settings set up yet but the user setting record must have a user associated with because you just can't have a user setting record setting in your database with no user associated with it that wouldn't really make any sense because in order for the user setting to be created in the first place there has to be a user that was associated with it okay so what we'll do is we will set up a user ID this will be this has to match the ID of the user as well okay oh whoops the type is not ID but type is number so let's go ahead and use the field decorator again and we also do need to import the int uh constant this is the graph K scaler type and then we're going to call this decorator function and then pass in this uh type function or return type function because we are dealing with a numeric data type so I'll add some other fields as well uh I'll do one for receive notifications this will be boine value uh I will set a default value for this so default value will be false nullable false but actually I don't even need to include that because by default it will be non-nullable let me copy this let let's do receive emails okay and then uh yeah we'll leave it like this for now let's just keep it very simple all right now what I'm going to do is I'm going to go back into my user. ts file the user model and I'm going to go ahead and Define another field for the user setting which is going to map to this user setting type that I just created so I'm going to create a property called settings and and this will have the type user setting just like that and we're going to import that from user setting and now what I'm going to do is I'm going to use the field Decor like this and we do want you we do want settings to be nullable because like I said there is a possibility that settings could be undefined because maybe the user did not set it up of course this depends on how you set up your project sometimes s you might just you know populate the user settings field for them by default when they create their account sometimes you won't so it's really up to how you want to set up your app for now I'll just leave it like this where we do have the settings as knowable so for our code itself we will use the question mark operator the optional operator so that way typescript knows that settings is optional for graphql we do need to say that this field is knowable just like this okay Noble set the true and if I were to go into my schema now you'll see that it generated this user setting type uh we have all three of our fields that are all non-nullable we have uh let's see we have our type user and notice how for settings user setting is uh nullable because it doesn't have the exclamation mark next to it all right so everything's looking pretty good we have no errors whatsoever so that's good if I go into the graphql playground the schema should recognize user setting great okay if I were to try to get the settings value of course I need to make sure that I provide sub fields for settings because it is an object and this is where you need to also understand how graph C works when it comes to uh fields that are nonscalar or in other words that are objects that have other subfields like this one so basically basically it's kind of like a recursive process where graph kill will keep on uh it's it's a process called resolver chaining resolve chaining where it'll look for a field if it's an object that needs its fields to be populated with the correct data then it will populate that data okay so for example inside settings we only have user ID we have receive emails and receive notifications but what if settings also had a field that was mapped to a custom type kind of like how user is mapped to user settings user settings might be mapped to uh a more sophisticated object as well so maybe we might have I don't know I'm just going to make something up um maybe let's let's pretend like notifications is its own field and it is an object and it kind of just goes down this hierarchy so it'll chain all of these resolvers and they'll retrieve all of the necessary data in needs to populate each corresponding object okay so let me just remove this so in this case right now what happen is when we query when we use the get users query it will get all of these scalar values ID and username it see settings settings is not a scalar value it maps to an object and what we need to do is get all of the necessary data so user ID receive emails and receive notifications and populate those fields so that way when we return it back to the client they get those fields okay hopefully that makes sense but it's pretty much like a recursive process where it'll keep it'll keep uh going down that hierarchy until there are no more objects until it pretty much bottoms out at scalar values so there's no more objects left to resolve then it'll just stop okay if I click play you'll see that now I get a list of all the users but notice how all of the settings are null that's because we don't have any settings that are associated uh with these users and we also did not resolve the settings field so now I'm going to show you how we can actually populate this settings field okay so what we'll do now is this we will go ahead and go into we'll first create some mock data for the user settings mock user settings. TS okay and then let's create the variable and we want to make sure we map our data accordingly so we need user ID receive notifications and receive emails so let's do this user ID one uh receive notifications false receive emails false okay so pretend this user settings data is its own database table or its own database collection if you're using something like mongodb for now I'll just have only two uh user setting objects so I'll set the ID uh one and three and we'll change up the values a little bit all right so we have our mock user settings now let's go ahead and actually resolve this data with the correct user so notice how that we have two only two objects so this will imply that the user ID of one will correspond with this uh user settings right over here okay and same thing with user ID of three now it's of course it's also up to you when you are writing your application that your user and user setting IDs are going to be consistent with each other you need to make sure that as you are creating your records that when you have a user and then you create a user setting for them that the user ID is going to reference the correct I'm sorry the user settings user ID field is going to reference the correct user ID itself that's the way how you can know that this user setting belongs to this user okay so what we're going to do now is we're going to go back into the user resolver.com and create a method that is going to be responsible for resolving the field for settings so what we're going to do is we're going to uh let's see let's call this um gets settings or get user settings okay and then what I'm going to do is I'm simply going to go ahead and first use a decorator this decorator is going to be the resolve field decorator let me import that from nestjs graphql package and then I'm going to annotate this get user settings function with the resolve field decreator okay so now what I want to do is uh first I want to actually specify what it is returning so we can use this we can pass in this callback function and uh we are not returning an array but we're returning the user settings which is just a single object so we're just going to reference that user model that user setting model okay and that's imported from up here all right so now here's the here's another thing that we need to also do inside this get user settings method we actually need to make sure we know which user setting to get and remember how I said earlier we need to make sure that we have some unique value that's going to correspond between the user setting and the user itself so we need to First actually know one which user we are trying to resolve the data for but how would we get access to that user though okay because for example we have a bunch of different users we have three users in this case we want to make sure that we are resolving the settings property for this user this user and this user but how do we actually get access to that user's data because we have the ID for that user and that's the way that we can use uh that's the data that we can use to actually get the user settings how do we get access to that so what we can do though is there's actually this decorator called parent and we're going to import that from the nestjs graph package okay so I can use this at parent decorator and this actually gives me access to the parent of this field of this settings field and it makes sense because if you think about it we have this user setting property right over here it has a parent it has the user as its parent remember how earlier I said that user by itself can exist without a user setting record however user setting cannot exist without the user record it's kind of like a parent to child relationship okay um think of it like this the parent alone can exist without the kid but the kid alone cannot exist without a parent you know assuming it's a baby of course the baby would need a parent to take care of it obviously so it's kind of like that an now hopefully it's not the best analogy but hopefully it makes sense okay but that's really what's going on here that's actually a common analogy that many people refer to when they talk about these types of relationships you have a parent to child relationship where the parent can exist without child but the child cannot exist without the parent and that's this exact situation right over here okay so in this situation we can get the parent by using the parent decorator and then I'll just call this user and let me make sure my user model is imported so so this is the argument name of the parent so this right over here gives us the access it gives us access to the parent of the field of the settings field okay so that way it'll know which parent to actually use the query for the correct user settings now before we do anything else though we do also need need to pass in this optional value but it's no longer optional because we're trying to resolve a field okay so we need to actually pass in this function and we need to return whatever the parent is so that's going to be user the user model itself this basically tells the resolver that user is the parent okay so you need to do this if you are using this resolve field right over here okay because user setting has a parent which is user so hopefully that all makes sense so now let's actually before I do anything else though um I'll just actually console log user just to show you what actually happens in the logs when I try to query um get users and then we try to get the settings resolved if I click play you'll see in the console see crash seems like nothing is actually been logged I think we actually do need to return something so let's just do this let's return and EMP the object for now seems like nothing is working in that case not sure what oh you know what it is um hold on yeah I need to do one more thing so you know no notice how right over here in uh the user type I have settings and I have get user settings uh I actually don't want this part right over here because actually if you see right over here it's going to expect me to do get user settings in order to get the actual user settings so if I do that you notice that let me show you see now it's saying cannot return null for non-nullable field but you'll see now the logs are occurring right over here but of course I don't want two of these things to do the same thing uh and the reason why this is happening is because um I have this method name right over here as get user settings and it will actually generate that as its own uh field right over here but I don't want that though so what I can do is I can actually pass in an argument or an object and I can set the name to just be settings so that way it'll match this setting is right over here and you can see now that method name is gone so this allows me to actually keep the same name while also keeping a different method hopefully that part makes sense so now let me get rid of this and if I call settings now you're going to see I get an error is this cannot return null which of course this makes sense because we are returning an empty object but I wanted you all to see the logs right over here you can see that all of the objects are being logged these are all of the parents for the user setting field okay so each parent of course is going to have its ID so I can reference the ID to find the correct user setting for that user so that's what we're going to do what we're going to do is we're going to reference mock user settings and all I'm going to do is just callind and we imported it up top over here so we imported mock user settings we're going to call find and I'm going to search for a setting where the setting. user ID is equal to user. ID okay let me remove the console log now of course this is also going to error out if it returns a null value so we do need to actually make sure that this query is uh returning a nullable value right now you can see that settings um expects a non-nullable value so we do need to change that and what we need to do inside this resolve field uh inside this object we just simply pass in nullable inste true and then when you look at the schema you can see now user setting it no longer has the exclamation mark you have to also make sure you do it for uh this as well okay well actually maybe you might not need to not too sure let me if I remove that yeah actually you don't need to worry about this part because the resolve field is what is actually taking care of it for you but I'll just leave it like that for now just to just because it doesn't really affect it much anyways okay but now that user setting is no longer a non-nullable value so it can be nullable so since do find will by default return a undefined value if it cannot find the corresponding user setting or if this predicate fails then it'll return on the find which will resolve to null and graph Q will take care of that for us so now if I click play notice how now I don't get any errors but you'll see that for uh the user ID of one I get the correct settings for user ID 2 I have no settings because I don't have any settings for user ID of two but for user ID 3 I do okay so hopefully that part makes sense so now this is how it resolves the data okay you get access to the parent you figure out what unique value you need from the parent to query the data from your database to get the corresponding field that relates to the actual parent data itself in this case uh we want to figure out which user setting relates to our corresponding user okay so hopefully all of this stuff makes sense now I do also want to mention one thing though right now let's pretend that we have a database connection let's say we're not using any mock data at all okay if you were to actually take a look at this right because the order of operations is pretty straightforward we we call get users or actually we're not using get user by we're calling get users okay so we're using the get users query so it goes over here first and then since it needs to resolve the user settings field it will go down over here okay so this right over here alone is a database call okay we're calling a database and returning the data this right over here inside this get user settings method this return mock user settings.in would also be another database call okay so in this implementation you actually would be calling the database twice and then you would be joining the data all together and sending it back to the client now you can start to see it being a problem when you have a bunch of different fields that are objects that need to be resolved with its correct data because let's say if you had five different fields you can start to imagine that that's going to be five different database calls that you're going to need to make to the database to actually get the corresponding data and then join it together with just everything okay and of course that becomes a problem because that can slow down your application and it's not like you know the ideal solution if you're trying to really save on like you know read and writes now the other thing that I also want to mention is this is one thing that graphql solves is it allows you to take something that is non-relational from the database standpoint and make it relational okay so it's not necessarily a huge thing that's bad there are trade-offs okay there's pros and cons with using graphql and this is one thing that I want you all to be aware of now let's say if we were using a relational database okay you can still actually use graphql with a relational database like SQL because for example SQL databases take care of the relational data at the database level but here's the part that is interesting though because if you're using a SQL database let's say we're using my SQL and let's say we're using an orm like type orm which is very popular type Orum has tools where you can actually query um a record from the database and you can also query all of its relations all of its one to one relations all of its on to many relations and a bunch of different relations okay and all of that is done with one single query is the orm takes care of all of that for you you don't have to write any custom query yourself you don't have to make two different queries the orm does it for you and that actually is a lot better because instead of having you know a bunch of different queries to the database you have one single query that is made and it gives you everything that you need so I will say though in my opinion if you are using a relational database like MySQL or postgres and you still want to use graphql you can the only difference is that you probably won't need to worry about using the resolve field because the resolve field is from my opinion and from what we're observing we can clearly see that the resolve field is really used to retrieve value that is not necessarily Associated directly with the record like it it's not able to be retrieved immediately in one go that makes sense okay because let's say if I were using a SQL database I already have one way to get all the data using one query by using the built-in type RM methods why would I want to um call another query to get all the settings because in a relational database you can simply just write a query that gets you the user with its user settings in one single query in mongodb it is a little bit more complicated it's not as straightforward as um SQL but again with graphql you can kind of like bridge that gap of having relational without needing to worry about your database being relational okay so like I said in my opinion I think that if we were to use graphql with a relational database that would be totally fine you I would just avoid using the resolve field and I would just write regular queries that return to data the client side would still be able to retrieve whatever it needs to retrieve it's just that the server will return back whatever you asked for so you'll still um avoid the problem of over fetching okay it's just that um you'll be able to get all the data that you need and then get what you actually ask for and like I said when we actually see an example of how to use this with the database you'll start to understand all right so now I'm going to show you all how we can actually create data using graphql okay so many of you are used to or familiar with rest pis and creating data you would use a post request and send a request body in graphql there are no post requests there are what's called mutations and mutations are really just a way for you to really mutate data hence the name mutation so you can use it to create data you can use it to update data all that good stuff so what I'll do is I'll show you an example of how we can create a user so all it will literally do is it will take the user data and then add it to our mock users array in memory so when we uh query the users again we'll see the updated mock users okay so let's do this let's go ahead into the user resolver because we are creating user so it should be related to the user resolver itself and we're going to create a method and I'll call this create user and then we need to actually tell graphql that hey this is going to be a mutation so we're going to import the mutation decorator up top over here and then I'm going to apply that decorator I'm going to annotate this create user method with the mutation decorator just like that we also want to specify what the return value is when we create the user so inside this mutation decorator as an argument I'm going to pass returns and then we're going to um um return user okay all right so now what we want to be able to do is we want to be able to actually take in arguments so for example I'll I'll show you a really quick example using the same function on how you can take in a single argument and then I'll show you more practical case for our situation so for example when we when we want to create a user we need a couple of information we need the username we need display name you might have other fields that you'll need but username and display name are the most common one of course you typically don't create or you don't send an ID when you create a user you let the database generate it but in this case what I'll do is I will set a counter increment incremental ID I'll set this to three and I'll increment it uh each time or let me see um I kind of need this to be Global so that's not going to work uh I just want to show a really easy example so here's what I'll do is I guess what I'll do is I'll generate or not generate I will create it inside this file um incremental ID equals 3 again not the most practical solution but this is just for just a simple example because we don't have a database okay so what I'll do is I will use the args decorator and then I want the username so username will be a string and then I want the display name but display name could be nullable so I don't even need it but I will provide it as well uh display name String and then since display name is in fact knowable I will pass in this second argument into this second args order here for display name and I'll say that it is knowable so I'll set that's a true okay so now we have two arguments username and display name and we'll we'll increment the incremental ID from 3 to four and Etc whenever we create a new user so here's what I'll do uh const new user I'll create a new variable uh I will go ahead and grab the username and display name fields and then the ID I'll set that to Plus+ incremental ID so this will be a prefix incremental operator so that'll increment the ID to or that increment this variable from 3 to four and then assign it to ID and then what I'm going to do is I want to uh add that user to this mock users array so I'll just do mock users. push new user and then we will just simply return new user and let's go ahead and see what this looks like okay first let's verify there are no errors good or logs are good let's go back into the graphql playground if I go into the schema you can see that I now have this type mutation and then I have this create user mutation and this create user mutation has two arguments as a username which is non-nullable and then has display name which is nullable and then it returns user which of course is a non-nullable value so uh what I'll do is I'll create a new tab inside this graphql playground and I'll use the mutation keyword instead of the query keyword because I want to perform a mutation and I'm going to go ahead and use the create user mutation and this is going to be very simple all I do is I simply provide the necessary arguments that I need so I need username so I'll set this to be let's do Duncan and then let's do display name which is optional but we'll provide one Duncan okay and of course we can provide a pair of curly braces because remember create user even though it's a mutation it still also returns a value remember that so we can also specify what uh fields that we want to grab from that return value because it's an object so I can grab the ID I can grab the username display name anything that is of that is within the user I can also grab the user settings as well even though this user will not have user settings so if I click play look at what happens let's see oh I'm sorry I forgot to provide the sub fields for settings let's do user ID uh receive emails and receive notifications so now look at this I just created the user and then you can see that I have the idea 4 username Duncan display name Duncan settings null okay of course that's pretty obvious because we don't we just created this user and it's and in the mock user settings we don't have a corresponding user settings for that user okay but of course we can create a user settings but I'll do that in just a little bit hopefully this makes sense what we just did was we provided two arguments to create the user now of course while you can use these uh these as args like you can use the args decorator um you don't want to actually do it this way because let's say if you had so many uh arguments that you need to pass in to this mutation you're going to have a long list of arguments being passed in and it's just not going to look nice in your code so what I would recommend you do and is instead of using args you use what's called an input type okay and that is basically kind of like a way how you can set up a request body if that makes sense you pretty much it allows you to set up like an object that has all of the fields that are necessary for creating the user so I'll show you how to do that it's actually pretty simple so what I'll do is let's see I will go into uh let's I don't know I don't really know where to put this but I'll kind of go I'll create a new folder inside graph que I'll call this utils for now and I'll create a new file and I'll call this let's see create user input. CS so since we're using the code first approach inside this file we will create a class and I'll call this create user input okay and then we're going to use the input type decorator so I'll import that up top over here from nestjs njsg graphql okay and then I'll annotate this class with the input type decorator just like this and now we're going to define the fields that will belong to this input so this will just be again similar to when you're making a post request you have your Fields uh this will just be similar to that for a mutation so for our mutation we expect two arguments username and display name so let's set up the username first so username B string and we're going to use the field decorator so let's import that like this remember username is uh non-nullable okay but display name is nullable so what I'll do is I'll annotate display name but I'll also pass in um an object and I'll provide the property knowable and say that's a true and if we had any other fields that we needed to create the user we can add them over here so now this makes it more cleaner so instead of having to use a bunch of different arguments and make it look really ugly we can use a simple input type to um provide all of our all of our values okay so now what we can do is we can first remove these two args or these yeah these two arguments and then uh we'll still use The args Decorator though but we'll call this uh create user data and then we'll name the argument variable or the argument name create user data and the the type will be uh we we'll use the create user input class to annotate this argument over here okay let's import that up top there so that gets imported over here all right perfect so now we actually have to use this data to create the user um so what I'll do is I will actually destructure the values from this argument so I can just do that by simply kind of like using the bracket uh uh the uh curly brace notation so I can either do that inside the argument signature like this so I can do username and display name like that um or if you don't like doing that you can just simply do this const create user data username this name doesn't matter it's up to you how you want to do it but it still yields the same result okay now let's go back to our graphql playground let's refresh okay if I look at the schema now you'll see that we now have an input so we had type and now we have input create user input and if you look at the mutation it is now one single argument but it is this create user input type so now what we'll do is let's remove all this stuff right over here and let's call create user okay and now you'll see that it has this create user data right over here so instead of passing individual arguments one by one we can just put that all in an object so we have create user data is the name of our input or name of the argument and this is going to be an object so we'll use a pair of curly braces and then we just provide the property name that we need to provide which is username let's do Duncan and then display name Duncan as well and then when we receive the return value let's go ahead and get the ID username and display name so if I click play you'll see now we have the same result okay create user returns ID of four username and display name all right pretty straightforward hopefully that makes sense okay all right so let's let's do another example of IM mutation so this time we'll set up a mutation to create the user settings so here's what we'll do uh we're going to create another resolver so we'll go into the resolvers folder inside graphql we'll create a user setting resolver and this resolver will take care of queries specifically for user settings not user but user settings alone okay so let's export class user settings resolver so we're going to create a class call it user settings resolver let's use The resolver Decorator as well um let's import that up top here from sjs graphql all right and uh next what we're going to do is we'll set up a mutation so let's also import the mutation a decorator as well and we'll create a method and we'll call it create user setting create user user settings and then I'll decorate this method with the mutation decorator and we're going to explicitly say what it's going to return and it's going to return user settings so we need to make sure we import that user setting model that user setting type okay and that comes from this right over here we import this into the user setting res file and we specify this is the return value all right so now we're just going to do the same thing um that we did with the user when we created it okay so we're going to go ahead and create another input another input type to take care of creating the user settings so let's create a new file let's call it create user settings input TS and I'll just copy this part so create a class and then I'll use the imput tyte decorator uh and then now for the fields uh we need Let's see we need user ID receive notifications and receive emails because yes in this case you will expect the user ID because let's say for example the user does not have any user settings but let's say if they do configure the settings then you want to make sure when you create it that you have the correct user ID in realistic scenarios you'll pass the user ID from the front-end client back to the backend the graph K server so that way it'll know who the user ID who the user setting is for okay so we will need all three of these values so uh let's do this I pretty much just copied and pasted it because it's just pretty much the same thing the only difference is that we will not want default value um we do want this type returning in so let's Import in up top over there however uh for these two properties we definitely do want nullable to to be true right over here and the reason why is actually because um we actually don't know well actually you know for creating the user uh you definitely do want a default value because this is creating it's actually different than updating because we have we're actually trying to just create the record okay so we do want a default value set to false okay but yeah creating is different than updating with updating you do want knowable to be true for the fields but you don't want a default value because that would override any existing fields that you don't want to actually change at all okay but for uh the user ID yes this has to be mandatory because you can't create the record without the user ID all right so I think we have a pretty good solution here so let's kind of like close this out and now what we're going to do is we're going to use the args decorator let's import that up top here now let's do create user settings data and then let's go ahead and annotate the type to be whoops create user settings inputs okay all right so now all we really need to do next is just take this create user settings data and just add it to this array because we're going to have user ID receive notifications and receive emails all already because the front end in order to create the settings you need to already know who you're creating the settings for so the ID is always going to be required when you're calling this uh mutation which from the front inside you know let's say if we have let's say if we had authentication the front inside would have access to the user context they would know what the user ID is so they can use that to pass it in when they perform the mutation so uh let's just simply take create user settings data I will console log it just so we can see what it looks like but I will go ahead and reference user uh mock user settings push and then pass and create user settings data and then we'll just return create user settings data CU that's the return value and then now we need to of course register our resolver we need to register our user settings resolver so we're going to go inside app. module. TS and then we'll just do the same thing we did with user resolver and pass in uh user set settings resolver just like that verify that there are no errors in the console okay good let's go back into our graphql playground let's create a new tab and let's look at the schema you can see that we now have uh let's see the create user settings input and we have two mutations now so let's create a mutation we'll do create user settings oops so create user settings data so we need the user ID of course now one thing that we aren't checking is we aren't checking um if the user ID exists so that's obviously a problem but since we do actually have three users um and one of our users user ID number two does not have settings so we'll just use user ID 2 so this actually works out great for us so user ID 2 receive emails well actually since these two values are nullable let's actually see what happens if I omit them so let's get back to user ID C emails and receive notifications so if I click play okay perfect so notice how when I create the user settings uh user ID 2 is right over here receive emails is false and receive notifications is false so that's good of course I can't uh make this I can't make this mutation again otherwise it's going to just add the same record into the array and we're not doing any uh unique checks okay but what I will do though is let me actually like restart my server and let me just show you what happens if I set receive emails to True okay because you can see that there is a default value that I think appears right over here or maybe it'll tell you right over here yeah so right over here uh input create user settings input receive notifications it's not um it's not required so it doesn't have that exclamation mark and then you can see right over here boine equals false so that's default value so that's good okay so let's say if I set receive emails to true but I don't set receive notifications and if I click play you'll see now it's receive email Emil is true receive notifications false so that's perfect now if I go back to the get users Tab and if I were to click play now all of my users have settings you can see now I the user of ID number two that I just create the settings 4 has user settings so that's perfect so that's how you uh can create a mutation for this situation all right so the last thing that I'll do for you all is show you how you can integrate uh a SQL server with type orm as the object relational mapper with graphql okay so of course make sure you have um a SQL Server already installed on your computer if you have Docker you can just simply set one up with Docker it's actually very easy and you don't even need to install a SQL Server you can use whatever you want by just pulling down the docker image and running it as a container I'll be using my SQL though but if you use something like postgress or Maria DB or something else that is SQL related you just need to make sure you install the correct SQL driver okay so what I'll do is I'll install a couple dependencies in the project so I'll install at nestjs typeorm so that's the type RM wrapper um that's the nestjs type RM wrapper we need the actual type RM package and then since we're using MySQL we're going to install MySQL 2 okay and that should be it for that okay of course if you're using postgres you just need to make sure you install the correct Pocus driver you can easily find that off of Google so I encourage you to look that up just simply search postes uh node.js driver and then you'll find a bunch of different solutions that will work though the documentation on njs should have it somewhere okay so let's go ahead and install these packages once we're done we're going to configure our uh app module to register the uh type Aura module so that will take care of initializing the uh connection to the database and as well as a bunch of other stuff so let's just wait for that to happen shouldn't take too long there we go let's go back to our code and what we're going to do we're going to go into app. module. TS and I'm going to go ahead and import uh let's see we want to import type or module from type or now let me actually move this up top right over here so we're going to register the type orm module so we're going to reference type orm module and then we're going to call for root and this is where we're going to pass in our database configuration now normally I would encourage you to put this in an environment variable but just for the sake of this tutorial I'm just going to hardcode all of my values over here but like I said for an actual application that you're building definitely use environment variables so I'm using MySQL so for the type I'm going to set this to mySQL the host is going to of course be Local Host because I'm running this locally I'm running my database locally the port by default it's 3306 and that's actually the port that my SQL Server is running on the username for my database is test user password is test user um for database I think if I remember correctly you do need to create the database uh manually and then then type orm can then initialize it I don't remember entirely but uh if that's the case then we can just do that I'll just set this to uh graphql tutorial or graph qore tutorial and then we do need entities so let's do set that up that's going to be an array of entities and it will set synchronized true if you're using type of room for production do not set this to True set this to false this only good for development but what this will do is it will actually synchronize your database based on the updates of your entities okay so I can see that I am getting errors in my console which is good because at least gives us feedback uh seems like it says access denied um yeah unable to connect to the database I think it's because well I don't know if it's because the database does not exist but what I'll do is I'll create the database so let's do create database graphql tutorial and then that should be fine so let's see if that fixed it oh I'm sorry I forgot that my password is actually test user 123 okay there we go um okay so let me actually I'm just out of curiosity let me do this drop database tutorial I think if I do that it will not create the database for me automatically should give me an error I think yeah so you do need to make sure you create the database ahead of time before actually running your project because you can see right over here it errors out and says unknown database okay so yeah the first error that I had was I put the wrong password but to verify yes you do need to create the database first now our connection uh works so we're good to go all right so now here's the other part that we do need to do of course um we do need to uh set up entity okay and if you have used type run before then this should be very easy for you but here's the problem though uh the question that you might be asking is do we need to create a brand new class um for our type or orm entity to represent the data from the database and the question the answer to that question should be no because your data in the database should actually be very very if not 100% identical to your graph ql data as well so you see over here you have data for user okay all of this data over here that you're using to model your graphql response should actually also reflect your database as well in rare cases you could create separate entities but you don't need to because it's just going to be very redundant and it's going to be hard to maintain because if you change one thing um on one side let's say if you change one thing for the type or mty you're going to have to change it for for the graph K model as well and it just becomes annoying so here's what I'll show you how you can actually use one single class for both type orm and graphql okay here's what we'll do uh what we're going to do is we're going to use the same class but the nice thing is though we can actually use different decorators from different packages from the type r package specifically and using those additional decorators we can add additional metadata to these properties so that way it will be used for the context of type RM so I'll show you an example so uh right over here up top in the user TS file I'll go ahead and I'll import entity column primary generated column from type orm okay so to tell type RM that this class is going to be in type RM entity we need to use the entity decorator I'll set the name to be users like this okay to tell type of R uh that you have an ID that's going to be autogenerated you're going to use the primary generated column so I'll do that up top here and yes you can use multiple decorators for um a field okay so we have primary generated column right over here and then for the rest of our fields we also want type AR to know that these are also going to be columns as well so I'll use the column decorator that is from type RM and this should have no effect with our graphql server at all okay everything will still work just fine so you'll see that right over here I can still query my users if I refresh Let me refresh the graph kill server I can still query everything I can still create a user I can still create user settings everything works just fine okay all we're doing is we're just reusing this class and providing metadata for the class and that's really it type RM is going to ignore the other decorators because this isn't apply to it okay so now let's go ahead and uh do this let's import this user entity into this entity array so that's just this user class is going to be imported from this graph models user. TS file it's going to be input up here and we're providing it as an entity for type RM okay uh so now we do get an error of course because we need to do the same thing for user settings because remember how I said earlier in the tutorial that user and user settings pretty much have a one toone relationship okay so we need to do the same thing for user settings so what we're going to do is import those same decorators from type RM so we need primary well actually we won't need primary generated column though I think for user setting mainly because um that is going to be set and not autogenerated but it will be a primary column though instead of a primary generated column column entity so we'll set this and I'll set the name to user settings so user ID will be primary column not primary generate column because we're not going to be doing any autogenerating of the ID it's just that whenever we create the user uh we don't have the user setting created just yet but then when we do create the user setting we are manually setting the user ID okay so let's set the column right over here or these two okay and now we'll import user settings um let's see it's these right here user settings user setting okay and let's see what happens okay uh now it says data type user setting and user. setting is not supported okay the other problem here is that we need to actually tell typo remm that this is a one:1 relationship and that's actually pretty easy Al so I'll show you how to do that so do is write over here in the user. TS file we want to say hey look this settings property the settings field is a one toone relation so what we can do is we can can use the one to1 decorator that comes from type RM to denote that okay so uh let's see right over here from type RM we going to import one 12 one then what we're going to do is since this user um since this user object is the parent we're going to do a couple things well actually I'm sorry we don't need to have the column fi for that sorry it's been a while since I've used type RM so I do apologize for that so I'm going to remove this column decorator on the settings and I'm going to set this to one 12 1 instead and this will have a callback function that will uh let's see this is user so we need to pass an user setting right over here and then right underneath we're going to use the join column decorator from type RM so I'm going to import that up top over here so what this will do is when you actually query your data you'll actually be able to reference the settings part in type RM okay and now watch this we have no more errors look how beautiful that is no more errors okay but none of the things that we just did with type RM to our class will affect our graphql stuff at all okay so and that's great like I said and that's the beauty of decorators okay that's beauty of decorators is type Oram will interpret this class and it'll read whatever decorators it needs to read and it'll ignore what it doesn't like for example typ doesn't recognize this object type decorator has nothing to do with it so it's going to ignore it okay it's really just looking for specific metadata that it needs to map the class appropriately to um the database table there will be a issue though if let's say if the metadata does overlap but I don't think that will happen in this case okay all right so we have our first uh two entities set up let's go into our SQL server and let me show you uh what our schema looks like so if I do I think describe graphql tutorial no I have to go to use graphql show tables and now you see how I have two tables I have one table for users and one table for user settings great so we can actually persist to the database so let's actually do that so we can actually get rid of our um mock data right over here we we'll leave it alone because we might write some tests later on but we don't need to worry about using that anymore because we have a database so what we'll do is first let's actually uh do this let's modify our user resolver to actually hit the actual database Okay so so we actually get the actual data from the database itself not from the mock array let's do the easiest case first which is get users okay so in nestjs there's a pattern that they encourage you to follow and that's the controller service repository layer in this case we don't have controllers cuz controllers are for rest end points we have graphql so we can ignore the controller part and instead just have a service layer the service layer is primarily responsible for performing business logic um and it's also typically responsible for interacting with the data access layer which is the repository layer so in this case it would be responsible for interacting with the type database as well okay so just to keep things organized because I didn't create any modules at all for our project so what I'll do is I'll create a quick user module so we'll do this users and I'll create a users. module. TS file okay and then what I'm going to do is I'm going to create a class called users module just like that and then to to tell nestjs that a class is in is a class as a module you use the module decorator and that comes from nestjs common and then you want to have any Imports any controllers in this case we don't so we don't need that uh we do possibly have providers and I think that's really it Imports control yeah Imports and providers are going to be the main thing okay uh so what I'll do is I'll also move the user resolver um and maybe even the user settings resolver into it typically though you want to keep each module you know uh containing its own related business logic so in this case user settings is actually kind of different logic than user itself some can say that they are related to each other but in this case since they are separate um you know like I said we're not going to make things super complicated so for now what I'll do is I'll just move the user resolver into uh users modulate over here what I'm going to do next is inside the app. module TS instead of adding this user resolver as a provider I'm just going to remove that for now and I'm going to remove this UT up top here CU what we're going to do is we're going to actually add the provider uh we're going to add the user resolver as a provider for the users module just like this so user resolver so now the users module has everything related uh to user business logic okay and then what we're going to do is we're going to take the user module and then add that as an import inside our root app module right over here so what this will do is it'll basically take all of its Imports and providers over here and then kind of like resolve it inside the root module itself so this is a way to kind of keep things organized so you don't want because you don't want everything all in one single module you want to you know be able to kind of like separate it because it also allows usability as well so this is kind of like uh a good way to separate concerns and it's good practice as well so that's why I'm doing it just to show you all okay so now you'll notice we actually don't have any more errors anymore because right now user module has the user resolver as a provider and app module imported users module so if I go back to my graphql playground I have no issues with using any of these queries it's almost as of like nothing happened okay uh so now the next thing that I'm going to do is I'm going to set up a user service so I'm going to go ahead and call this uh user service. CS okay actually um yeah I'll leave like this for now uh what I'll do is I'll create a class and I'll call this user service and then I'm going to go ahead and use this inject injectable decorator because this tells nestjs that this is going to be a provider okay and it also ensures that uh when it creates the instance it creates a Singleton of it and then it'll take care of all the dependency injection because that's what njs does underneath the hood it actually uses the pendency injection to resolve dep pendencies so that way it doesn't create multiple instances of the user service okay additionally though if you want to you can create an interface and um Define all of those um abstract methods I'm not going to do that just to save some time and avoid making things super complicated but I do encourage you to do that so that way you're following good programming practice and what NJ encourages so what I'm going to do here is uh I'm going to go ahead and set a Constructor and remember how I said earlier the user service is responsible for interacting with not only the is not not only performing business logic but also interacting with the data layer so this is where we're actually going to be able to talk to our uh database using type RM so to do that we actually need to use what's called a repository okay and we're going to use this inject repository uh decorator which for some reason it's not recognizing it in my typescript code but I can just import that inject repository and this should come from at sjs type RM I believe yep perfect okay and so what this will do is this will take care of injecting the correct repository for the entity that you're trying to um work with so if I'm trying to get all users then I'm going to inject the user repository so I'm going to do this I'm going to pass in the entity so this is the same entity that we are using for graphql and type RM the same class right over here so we're going to pass that in and we need to make sure we import that so next thing that we'll do is we need to actually of course give the argument a name so I'll do private uh users repository and and I'll type annotate this to repository user like that I do need to import repository from type where actually I think it comes from it might actually come from type orm not too I don't remember yes it does come from type RM just double checked there we go okay so now what we can do is we can actually interact with this user repository uh we can call methods on the user repository to retrieve whatever data we need but before we can do anything though um we need to actually first uh make sure that uh we are providing this user right over here all right so now before we can even use this user repository right over here uh we need to first of all provide our user service inside the user module so we're going to do that so let's import user service class and then that's going to be added as a provider now you're going to see that if you look at the console logs right over here we're going to get an error and that's okay because there's still another step that we need to do before we can actually use the user repository okay you'll see that right over here it's complaining about uh if user repository is a provider is it part of the current users module okay so whenever you need to use an entity Repository for um to interact with the database you need to actually register it inside the module itself uh so what we need to do is inside the users module inside Imports we're going to reference type orm module and I do need to import that so import type orm module from uh njs typ RM and then we're going to call call the for feature method and then we're just going to Simply pass it in an array an array of all of the entities that we're working with since we're only working with user currently we're just going to pass in the user entity okay and that's it and now you'll see that the error goes away because we actually added this entity in the scope of this whole module type orm needs to know that so that's why we needed this step all right so now we can actually interact with the database we can uh reference this you know user let me just show you real quick we can reference this user repository uh property and we can see that there are a bunch of different methods that we can use to retrieve data or create data okay so what we'll do first is we'll create uh a method inside user service uh that will get us all of the users from the database so that'll just simply look like this I'll do get all users or I'll just do get users and I'll just simply do return this sty user repository and to get all the users you just simply use the find method that's it this will give you an array of users and this method is asynchronous so it'll return to promise so we need to make sure when we call this method um get users that we awaited okay because this will return a promise and get users is now asynchronous so we need to await that call okay so let's go into user resolver let's go back into get users right over here so instead of returning mock users now first let's actually make this get users method async and then we're going to do one more thing we need to actually inject the user service instance into the user resolver but that's very easy so like I said you should already know this if you use nestjs so I'm not going to really explain too much about it but all we need to do is just inject it by simply just creating a Constructor and there's two ways they can do this you can either use inject like this and then you can actually use the user service class as the token and then private user service and type an with user service like this okay then you can actually do uh you can reference this sty user service and then call get users like that okay the other thing that you could do to keep things simple is you don't even need to use this inject decorator you just do private user service user service like that okay I'll leave it like this for now just to save some space but let's go ahead and call this do user service and call get users and I actually don't even think we need the Asing keyword as well because we're just returning this data and nestjs will take care of resolving it for us asynchronously because we're not using a weight as well so we don't need that so uh there are no errors in the console that's good let's go into our graphic fuel playground and if I click play uh no errors which is good but it does return an empty array and that's perfect because we don't have any data in the database at all if I were to use the select asress from users query we can empty set because we don't have any data okay well let's change that let's go ahead and modify our mutation instead of actually adding the data to the mock array let's actually add it to the database okay so what we'll do is we need to First go back to the user service file we need need a method to actually create the data in the database so I'll create a method called create user and what I need is I need the username as well as the display name display name is optional of course so we don't necessarily need it but we will provide it if it is provided as an argument in the object so let's do this um let's see I want to see if I can reuse create user input yes I can reuse this class so that's good uh so what I'll do is I'll reuse this class I do want to actually mark this display name as uh optional so what I'll do is this create user data and then I'll reuse the create user input class okay because we can because it's the same thing if you don't like to do that you don't have to but um I'm just going to keep things simple so I'm going to reuse that class for now because it's the same exact thing anyways okay uh and then to save the data to the database what we need to do is we first need to create a variable called new user and then we need to reference the users repository and then we need to call create this is a synchronous method so we don't need to await it and then what we do is we just pass in the appropriate data so we pass username or display name in my case I'm just going to just pass I'm just going to pass in the entire create user data object because that will have username and display name once we create this object we need to actually save it to the database okay and we do that by simply calling this uh user repository. saave we pass in that partial which is what this new user is and that's it and this will actually return a user or a promise user so let's actually just return this call we don't even need the Asing keyword because we're just returning this and then in the user resolver all we need to do is we can delete all this stuff now and just return this. user service and call that new method that we just created create user and then all we're just going to do is pass and create user data just like that very simple okay let's just double check our logs make sure there's no errors okay now let's go ahead and try to create a user uh let's see okay yeah username and display name let's click play and there we go we have no errors at all we have an ID of one usern name display name if I go into the database you can see that I have one record in the user database that's perfect let's try to create a record without a display name let's make sure nothing errors out so let's set the username to ansen uh so now you see how there's a problem and this is actually type orm failing because uh graph knows that this is a knowable field but typo does not so what we need to do is we need to go into the users module and where display name is right over here right inside this column decorator as an argument we can actually pass in nullable set true and that should fix the issue for us so let's go back here and let's click play and see how now I can actually omit the display name value and it just works fine so let's create another record uh set display name to Jack and it works perfectly okay and if I go back to my get users query I can get all of the users um okay yeah this is is fine it's working appropriately uh the settings the user settings is still uh being resolved with the mock data which we will change so don't worry that's why you're seeing this settings part don't worry about that because it's still using the mock settings but it's still working fine though because we actually have users now that are being returned from the database and that's great all right so let's take a look at what we have so far so um let's see we have create user and we have uh get users let's fix get user byid so now I'll show you how we can simply just quer a database based on an ID for the user and that's going to be very easy as well we'll create a method inside the user service class called uh not create sorry let me go up here get user by ID this will expect an ID which is going to be a numeric value a number and all we need to do is just call user repository find one and then actually I think we can do find one by and then set the ID like that yep it's find one bu not find one sorry so let's go back into the user resolver and instead of referencing mock users we now will do this. user service get user by ID and then pass in that ID and let's check it out so since our data is persisted we should be able to get the user by ID so I'll create a new tab for this query get user by id id will be let's do two let's do ID username display name and settings for settings we'll do user ID see emails okay and there we go we do get the actual data from the database okay this is the actual user that we created earlier okay and we got it by the ID all right very very very simple stuff hopefully that makes sense so so far we fixed get user by ID and get users and also the create user so now let's go ahead and uh migrate user settings from using the mock data to actually the real data so first uh what we need to do is we need to actually have um a way to create user settings first okay but we also need to work with the user settings repository because remember user settings is its own entity it's not uh it's not part of user at all okay so in order to modify stuff with user setting you need to work with the user setting repository so just to keep things simple and avoid creating a bunch of different modules I'll just keep the user setting service inside this users folder so I'll create a new file and I'll call this user setting do uh user setting service.ts like that and it'll be the same thing it'll be a class with the name user setting service so exper class user setting service and we'll use the injectable decorator to tell type RM or I'm sorry type tell nestjs that this is um a provider of course it doesn't want to Auto Import so I'll just copy and paste that right there all right so now we need to actually inject the repository the same thing that we did with the user service so again this should be very straightforward if you've worked with njs already so we'll just do inject repository and I do need to import that as well okay and then we're going to pass in the entity that we want to work with so that's going to be user setting and then we just need to give our uh Constructor argument a name so user setting user settings repository and then we just type annotate it with this repository generic type and set that generic type to be user setting like that I do need to I do need to import repository from type RM so let me do that okay so we're done with that so now let's go ahead and create some methods inside user setting service so that way we can actually create the user setting and also get the user settings so first one that we'll do is get user settings um by ID or get user setting by ID so this will take in the user ID itself which will be a number and then we'll just simply need to call the fine whoops sorry this do uh why is this oh I'm sorry I need to add the private keyword in front of this in in front of user setting Repository so now I can reference this do user settings repository find one by and then user ID so this will search for it based on the user ID so this will be used when we actually take care of resolving the data okay or resolving the field 4 settings now let's go ahead and set up a method to create user settings and we are going to reuse um the create user settings input class okay right over here um let me see let me just make sure I have this correct as well as set up properly for typ okay yes we do okay perfect and I think this should be okay um let me also see this class as well okay yeah I think this should be fine but I think I do need to do one more thing though in the column section I do need to set the default Valu to false for both because these could be nullable well actually they won't be nullable because we have a default value but I'll set I'll set the default value to false okay so what we'll do is we'll reuse this create user settings input class to type annotate the argument that we're going to pass into create user settings so call that argument create user settings data and I'll type annotate with create user settings input class and then all I need to do is the same thing that I did uh when I created the user okay it's a two-step process so first you create the actual partial of the user settings so const new user setting equals this do us uh user settings repository do create and then we just pass in this object into that create method meod okay and then uh we'll go ahead and return this. user setting repository do saave new user setting okay perfect uh so now what we'll do is we need to also go into the users module we need to add this user setting Service as a provider same thing that we did for user service let's import that and again you should see the error that's complaining about the user settings repository and again that's the same reason that's the same error that we had when we tried to uh add the user service provider but we didn't have the user entity registered in the scope of our user module so all we have to do is just go back up here where we have our for feature method being called inside this array you just have to add the user setting entity okay and that's the same class that we created that we used for graphql okay and now the error goes away and there we go so now we can actually go back into the user setting resolver and well yeah let's do this let's first modify the user settings resolver first so instead of adding it to the mock user settings array uh uh we will go ahead and first uh let me see you know what let me actually do this as well because I just realized something because since user settings resolver is a provider for um the root app module when we actually try to inject the repository we need to redo the same thing uh we need to add it inside the root app module So to avoid re you know doing this over and over again what I'm going to do is I'm going to remove this user settings resolver as a provider from the app module I'm going to uh I'll leave the file here for now but inside users. module. TS I'll just simply import the user settings resolver class as a provider in here and it'll still work just fine all right so now inside our user us settings resolver let's go ahead and inject the user settings service that we just created private user settings service user settings service okay everything looks pretty good nothing wrong with this at all okay perfect all right so let's go into this create user settings method which is our mutation for graphql and instead of just returning this plain object that we pass in which is not correct uh what we're going to do is we're first going to let's delete that let's first create the user setting so const uh user setting equals and this time we actually need to use async AE so let me add the async keyword in front of this method and I'll await this uh create user setting called all so this. user setting service do create user settings and I'll just simply pass create user settings data which is the object that has all of the uh fields that we're using to create the settings okay all right and now what we want to do is we already have the new user setting created because remember this method itself uh created the par and then it saved it to the database so now when we uh await this method call it resolves the actual user setting record from the database so I can just simply return user setting just like that so let's test this out let's make sure it works console has no errors so let's go into create user I'm sorry create user settings okay and before we do anything else I'll quickly go into my database and show you what it currently looks like you can see that settings user ID is currently null okay uh so what we can do is we can actually uh create the user record but here's the other thing that we also need to do though is not only do we have to create the user settings but we also I forgot to mention this as well we also need to make sure we're linking that user settings to the correct user okay because it's one thing to create the new user setting but we need to make sure that since we're using a relational database and we already have a onetoone relationship between user and user settings that we're linking it correctly because if we don't uh these fields are going to be null and that's not good okay so to do that um we need to go right over let's see okay so right over here inside create user settings okay so when we create the data uh we're calling user setting service. create user settings okay that's fine then we go into user setting service and this is where we're working with the user setting repository so we actually do need to inject um the user setting or the user repository um so here's what I'll do I'm going to go ahead and inject the user Repository okay and that got imported up over here let's make sure there's no errors okay there shouldn't be because we're in the same module and both of these entities have been provided already so we're so we don't have to worry about that so we need this user repository because what we need to do is one we need to actually um make sure that the user actually exists so we actually do have to do a a check in a database so I'll do this very quick so con find user equals um let's add let's use async A8 so async wa this. user repository. find by find one by and we're going to find by the ID and we have the ID inside this create user settings data if we just reference the user ID property so if fine user uh uh does not exist we'll throw an error uh I think there should be a graphql ex exception class that you can throw I'm not too sure but um I'll just throw an error user not found okay uh if the user is in a database then what we'll do is we'll create the user okay we'll create the user settings uh we'll save it and then what we will do is we need to go ahead and uh actually update the user itself so I need to go ahead and do find user. settings equals saved settings like this and then I need to go ahead and call this. user repository. saave find user and then I can return saved settings like that so it's a good thing I remembered that all right so let's go back into our code and let's go back to get users um seems like yeah it's still resolving the mock data we have because we haven't changed that yet but let's create uh a user settings right now okay so pay attention to the table right now I have three users okay we're going to create user settings for user ID number two uh so let's do that okay so it worked and there were no errors it seem like let's go into our database okay perfect now you can see that right over here settings user ID which is um going to be the ID of I'll show you right now so set what what setting user ID is that's actually the reference key that allows us to know which record this references in the user settings table so by us setting it to two that tells us that hey this record uh for Anon in order to get the correct user setting we have to reference this setting users ID which is two in the user settings table itself so that's how we would get the appropriate user us setting for the user okay so we have it working just fine so let's do the same thing for let's actually try to do this let's let's try to create as a user setting for a user that doesn't exist so we know we don't have a user ID of 10 and you can see that we do get an error so this is good and of course on the client side you would have to handle it accordingly okay but let's create a setting for user ID of one okay so that's good so now um we have user settings for user ID 1 and user ID 2 let's create one for user ID 3 perfect so now let's go ahead and go back into our user resolver so where we are resolving that settings field okay and then what we will do is instead of referencing the mock user settings is we'll actually resolve the data by actually querying the database okay so this is what we're going to do we need to inject the user settings service into this user resolver class because right now we're trying to query the user settings table okay and we have all of those methods defined in that service class so I'll add this in the Constructor private user service setting user service us user setting service sorry let me actually change this real quick user setting service okay and then what I will do is simply go to get user settings let me just make sure there's no errors of course okay good right over here at get user settings I'm going to go ahead and return this do user setting service and remember how I created this get user setting by ID well this is where it's going to come to use um we want to get the user setting by ID so we have access to the parent already so I can reference user. ID okay so this is good because now we can get a list of users and it'll resolve all of the settings correctly based on the user's ID okay so whatever the user ID is we'll pass that as the argument to get user setting by ID and of course we're assuming that those IDs are going to be consistent across both of the tables both of the records in the tables it's up to you to make sure that you do that so if I go back into my graphql playground now watch this if I click play now every single user has set settings and this is all data from the database okay that's all it is all right we have uh get users and then we have all of our users over here if I try to do get user by ID you can see that I have the user for ID number two and then its settings as well okay so hopefully that makes sense so now you all can see how powerful graphql with a database like SQL and an orm like typeorm is now this is the last thing that I'm going to show you all because I did mention earlier about um the problem with querying multiple databases and I'll actually show you real quick if I go into app and if I enable logging this will actually show you the queries that are happening okay you can see all these queries that are occurring right now um so what I'll do is I will uh call get user by ID or I'll I'll query get user by ID and now watch this we did one query for user okay and then we did one query for user setting you see how it says select user um where user ID is equal to question mark which is whatever the user ID that we passed in and then we did the same thing right over here select user setting where the user setting. ID or user ID is equal to whatever we passed in okay so that's two queries right over there now let me show you real quick what happens is instead of having uh two queries occurring let's say we want to get the user and all of its relations at the same time so what I'll do is I'll go over to well well first you know what let me do this let me actually comment out this resolve field query okay our stuff will still work fine so don't worry about that there there's no error right over here but what I'll do is I'll go to um the user service okay I'll go to where I am uh where I have the get users method and right over here inside this find uh method call as an argument I can actually specify the relations that I want and all I got to do is just provide the relation field name which in our case it's settings it's whatever this name is right over here and now watch this if I actually were to um let's see this should actually give us back am I using the yeah I'm using the wrong query apologies for that if I go over here okay see how now when I query uh get users it gives me all the the users with its settings now let me actually go back here and remove this okay notice how now it's null okay so notice how when I by default type RM won't give you those relations you have to actually opt in it you have to actually say hey I want these relations okay before though we were using graphql to make another query to get the user settings but with type RM when you're using a relational database you see how what I'm saying is you can select what whatever relations you want and it does it in one single query so let me actually uh add this right over here for find one by so I can add relations uh let me see I think I need to use a different method actually because I don't think I can yeah I need to use a different method for this let me try find uh um one where ID is equal to ID and then um relations settings okay so this is what the argument looks like and now watch this if I go back to get user by ID notice how I can actually now get the user by its ID and I can also get its relations I can get the settings and if you look at the logs over here you know let me actually uh let me actually reload everything okay so if I run this query again notice how now we only have one single query this one single select query okay that's going on um and you can see over here I mean up top over here it says select distinct distinct Alias user ID okay and then over here we have select user um let's see yeah so we really only have one query to the user table and then it's joining it with the user settings table and it's going to give you um the correct relation okay you can see over here I have user settings uh a user ID of two receive email is true which it is right receive receive emails is true uh let's say let's do receive notifications uh what the bottom line is yes it is it is correct so hopefully this helps you understand um why I was mentioning earlier about using you know something like SQL with graphql and it kind of It kind of it's not like unproductive it it it kind of just is a little bit contradicting to each other because when you use Gra fql you are primarily going to be resolving each field by calling either an API to get the data or a database or whatever external source to get data okay and that requires multiple calls when you have a database that's relational it can take care of getting all of the necessary data for you because that's the whole purpose of a relational database so you don't need to use graph cule for that so I bring this up because hopefully that will give you some context on when it's appropriate to use graphql with a certain database in my opinion I think graphql works best with a nosql database like mongodb but you can still use it just fine with uh a SQL database because for example I can remove this settings uh field and I'll still get only what I want however the database still will do that join with the user and the user settings table to get that single record with with all of the data it's just that the graphic server will ensure that it doesn't give you back the settings okay so really again you can't go wrong with going about it this way but like I said I wanted you all to see this for yourself so you can make an educated use case for your project well that's going to be it for this video I hope you all enjoyed it if you did please leave a like down below it really helps out the channel a lot if you have any questions regarding the tutorial or if you have just questions in general en you know just leave a comment down below I do my best to respond to all the comments whenever I can and uh if you want to you know subscribe to my channel I try my best to upload as many informative videos as I can and once again check out the description because there will be a link to the GitHub repository so you all can use it as a reference thank you for watching and I'll see you all in my next episode peace out
Info
Channel: Anson the Developer
Views: 6,046
Rating: undefined out of 5
Keywords: nestjs, graphql, typeorm, mysql
Id: CSfZmyzQAG8
Channel Id: undefined
Length: 142min 44sec (8564 seconds)
Published: Wed Nov 29 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.