Transcripts
1. Introduction & what this course covers: Welcome to this course. I'm excited to teach you one of the most in-demand web development technologies at the moment, which is GraphQL. GraphQL is a modern way of building APIs to create the back end of our projects. It basically provides a simple to use syntax to get the exact data we want to our front-end. We have lets say, a website or a mobile device or any other service. This introductory course, covers all the fundamentals to get you started, such as setting up our GraphQL servers, working with queries, mutations and subscriptions, how types work and the relationships between them. Written resolvers, and how to setup a real database and also interactively using PRISMA, along with lots more which you'll find as we go through the course. By the end of this course, you will know what all of these is and how we can apply them to all projects. We won't just be covering boring theory in this course. In fact, pretty much all the examples we'll cover, we'll make it into a course project. This will be a movie review based project where users can create a review, based on the movies in the database. You will learn how to interact with the server and also the database, post data such as new users, movies, and reviews, along with how to get back the exact data we want, such as listing reviews for particular users. How we can link relational data, such as reviews to movies, and also to the user who created it. This course is intended for beginners to GraphQL and also PRISMA and also even newcomers to working on the server side. However, I would recommend at least some basic experience of JavaScript or a similar language. This will really help you to get through this course. Also having a basic understanding of the role of a server and a database will also help you get the most as you progress through the course, so we hope you're ready to take your skills to the next level by learning GraphQL and PRISMA.
2. What is GraphQL?: Before we get to building a real GraphQL server. I want to take a moment to go over exactly what GraphQL is and why is becoming so popular. GraphQL was originally created at Facebook and is now an open-source projects. Is not a programming language, a framework or anything like that. It is a standard for building modern A-P-Is or generally sending data from a server to the client. In the web development world, it can allow data to be sent between a client and a server. A client being on the left-hand side of this slide. Which can be anything from a computer's browser, smartphone, or anything else which needs to get data. This communication is via H-T-T-P requests and the server over on the right. Which sends the requested data back to these clients. This usually consists of a Web server to deal with requests from the clients and also a database which server can get data from if needed before returning this back to the client. A popular way of allowing the client and server to communicate is by using what is called a REST A-P-I. An A-P-I is a set of rules to allow communication between different pieces of software. In our case, the client and server. Larger small companies often make data publicly available via an A-P-I. For example; Spotify has an A-P-I so we can access them music catalog. Meaning anybody could build their own personal music player and then use Spotify data to get songs, playlist, artist information and much more. Google also has lots of A-P-I too. For example; allowing applications to access Google Maps data or you can create your own video player websites and then use YouTube videos behind the scenes. Traditional A-P-Is often referred to as REST A-P-Is. However, do have some limitations with these A-P-Is. They generally have multiple Endpoints to get data. For example; this is Spotify base endpoints at the top, which is a U-R-L. Then below this, we extend this U-R-L to get more data such as an album by the album/id. Then at the bottom we can also add forward slash tracks to this U-R-L to get all tracks for this particular album. Based on our project which will be building in this course. Let's say we wanted to get movie reviews for a user. Using a REST A-P-I, we may need to make multiple requests to different end points to get all the data we need such as the users endpoint, the reviews endpoint, and also the movie endpoint. Depending on how the A-P-I was structured. This may result in getting way more information back than we needed. If we only needed the movie's title. We may still need to get back all of the other movie data too such as the ID, description, customer information, and so on. Along with making multiple requests, which can be time consuming. While there's nothing fundamentally wrong with this approach, GraphQL provides us with a better alternative. GraphQL only has one endpoint, minimum concerned one query for our data and it has the flexibility to only give us back the exact data we need. For example; A mobile device may not need to get back the same data as a desktop website because of the reduced screen size. A small device may just want the reviews basic information such as the author name and movie title. Whereas the desktop app may also want more information, such as the movie rating and the description. This can easily be achieved using GraphQL whereas REST A-P-Is may struggle to offer the same flexibility due to using these rigid endpoints. I will get lots of practice at describing the data we want to get back during this course. This makes GraphQL a really flexible, fast, and efficient way to get data into our projects.
3. What We Will be Building: As we progress through this course, we'll be creating a movie review based project. The whole idea is we can create users, we can create movies, and then each user can create a review based on the particular movie. Since we're using GraphQL which is a query language for creating the back-end of websites, we're not going to have a user interface to deal with for this project but instead we're going to use what you can see here, and this is called the GraphQL playground, which allows us to interact with all of our data whether that's stored in our project or stored in a database which we're going to be adding. If this all looks a bit confusing and unfamiliar, though what did you say? Yes, since we get lots of practice using a GraphQL playground as we go. As we go, we're going to be creating all the code we need for our server and store data in our database. We're going to be doing things such as performing queries where we get data such as movies. Here is a list of all the movies in our database. We're going to be doing the same for users. We'll write all the code to allow us to grab users, and any associated data, such as the user is linked to the reviews and also the reviews linked to a user and also to a movie too. This will give us a lot to go practice art, art in relationships between our different types. We can also do things such as grabbing reviews by user and GraphQl is really flexible, allowing us to pull back only the exact data which we want. All this data comes back from our database, structured like an object. It's easy to send to any front-end whether that's a website or a mobile device. All of this data will store inside a real database where we set the prismatic interact with our database. This gives us a much better visual representation. We can see our users, our movies and any reviews which are being added. We can also see any relationships. If we look at the movie, we can see the reviews and how many for each one. The same for the users. We can see how many reviews have been posted for each one, the connies, and then we can also be taken to that review. Back over in the playground, as well as reading data from the database, will also look at how we can signup users, will also look at how we can createMovies, and also look at how we can create reviews which are linked to the movie and the user. Another great feature of when using GraphQL is we can also use what is called a subscription. And this will allow us to subscribe to data. Every time the data changes on the server, it automatically pushes it to our front-end so we're notified of any changes. This is ideal for something such as a review. Each time a new review is being created, let's create a review just here. We then see this data pushed to our front end. We can keep on top of things as they change. Again, don't worry too much about what you see here. This will just allow us to interact with the data which we are going to be creating during this course. We're going to waste no time at all get to grips with our new project. I will start this in the next video.
4. Setting Up Our Project and GraphQL-Yoga: During this course, we will be creating a movie review base GraphQL server, which we've already looked at. To begin we need to create a folder for projects and I want to place mine on the desktop for easy access. I'm going to call this movie hyphen review. Then open it up in Visual Studio Code, which I'm using as my text editor for the course. Let's open this up and then drag over the project folder into VS code. You can of course use any text editor which you prefer. Before we do anything else, you will need to make sure you have Node installed on your computer. To do this, open up the browser and then we need to go to Nodejs.org. Click on the download for the latest version. Once this is installed, we then run through the installation just like with any of a download. I'm going to click on this. Continue through. Must agree to the licensing, and then install this on my hard drive. It should only take a few moments to install too. Once this is done, clear this out the and way then we can go back to Visual Studio Code. I'm going to open a terminal, I go to terminal and then new terminal. Down at the bottom you see the terminal has now opened and we can run some commands. The first one wants to do is to double-check the node and NPM has been successfully installed. We do this by checking node-V and this will give us the node version of the buck, which have installed. If you see an error rather than a version number, there has been a problem installing the Node and you need to go back and do this first. We could also double-check with Node Package Manager with NPM B. They should also give us the version of NPM will have installed and it comes bundled with the node download. Great. Inside the terminal we can run NPM in it. Hit Enter and this will initialize our projects. I'm just going to enter full options, keeping most of the venue's as defaults. The package name, I enter, the version description. The one changing onto make is rather than having the entry points as the index.js, I wants changes to source, so src/idex.js, enter and then enter through all the rest of the options. If we open up the sidebar, we can see inside of our folder we now have a package.json file. This contains all the information about our project which is entered. This is a pretty standard Node file and nothing specific to GraphQL at this point. Next we'll be creating our index.js file, which is added as the entry points. Go back to the sidebar in our open editor and create new folder in the root of our project, which is the source, so src. Inside here we can create our index page, which is index.js. Since GraphQL is a specification rather than an actual programming language, a library or anything else, we need to wait to actually use GraphQL in real-world projects. GraphQL as a specification is not specific to any programming language. Therefore, we need to use a package or an implementation for node, which will be using for this course. The one I'm using is called GraphQL Yoga. There are of course other alternatives but this is one I'm going to use for this course, since it has lots of features and it's easy to get up and running with. Go over to the browser and open up chrome. Then in a new tab, I'm going to search for GraphQL yoga. We can see it is a GitHub link here for GraphQL yoga, which takes us to the documentation. Other implementations are also available to, so we can use GraphQL, in other languages or environments such as Python. GraphQL yoga is an easy to use and setup GraphQL server, which will allow us to take advantage of all of the GraphQL features which will need such as queries, mutations, and subscriptions to name a few. Over in our project down to the terminal we can use NPM to install this package. NPM, which is for install graphql-yoga. Once this is installed we can use our index.js file. We've already begun to create. Make our GraphQL server. We'll begin in this index.js file by requiring the GraphQL server. So const GraphQL Server, I'm careful of the casing here, this is equal to require, I'm going to require our GraphQL yoga package, graphql-yoga. Next we need to create a new instance of this GraphQL server. I'm going to call this a constant name of server and set this equal to a new instance of GraphQL Server. This GraphQL server takes in an object and then here would pass in two properties. These properties are called typeDefs and resolvers. The first one typeDefs, and then resolvers. We can then this server which we created and then it call the start method. The start method then takes in a callback, which is a function which will run a this before the survey started. Simple console log will be fine for now. Let's turn this into a function, which returns a console log. This console log is just going to send out a message of server is running on localhost, pause 4000, and there we go. This is our basic graph SQL Server now in place. Next we will include some sample data to work with, before returning back, take a closer look at the typeDefs and resolvers which you pass into our server.
5. Including sample Data to Work With: Included with this course is a download which includes some sample data, have this download sitting here as a text file on the desktop. When we first get started with the graph QL, we may need some temporary data to get started with. Until we get our database setup later using PRISMA. So go ahead and download the sample data file, or if you prefer, you can type it out instead. We need to create new file on our project to copy over this sample data. So I'm going to open the sidebar, and inside the source folder, I'm going to create a new file called sampledata.js. Open up the sample data text file, select all, copy or less, and then paste this in to our sample data. This is just some information to get started with graph QL, we have an array of users, we have an array of movies, and we also have an array of reviews, module exports all of these we can use them in our project. We can then require the sample data in our index.js file, robin uses movies and reviews array, I want to do this at the top and set these as a constant. We can import all films same line. So uses, movies and reviews, and then we can require our sample data file inside here since this is not a node module, would you need to add the full file path? In our case, it's in the same location, so dot slash and then sample data. No need for the js extension. Now we need a way to make this custom data available to the rest of our server, and graph QL yoga provides the context object to allow us to do this. In side of our server. I'm going to add these two new lines make more readable, we have the typeDefs, the resolvers, and then next after here I'm going to add a comma and also pass in the context. We set this up as an object so we can pass in multiple items. We're going to add in the user's movies and also reviews, and these three are the same names which you pass it in up the top here as our constants. So the matchup inside the context, if this doesn't make sense at the moment, don't worry, this will become more clear what this does in upcoming videos. So for now, just consider this as a piece of setup work, and we'll begin to work with this data in the next video.
6. First Look at TypeDefs and Resolvers: So far we've created our GraphQL Server, passing in the typeDefs and also the resolvers. We have not yet looked at what these are, but both are very important pieces in the GraphQL puzzle. This is what we'll be looking at in this video. Starting with the typeDefs, which is short for type definitions. This is our GraphQL schema, which basically allows us to structure our data using types such as a string of text, or a Boolean value of true and false. Since GraphQL can be used in any programming language, we write GraphQL services using a special syntax called GraphQL schema language, which is pretty easy to get going with. We'll have lots of practice during this course. We then have the resolvers, which is where we ask our functions, which will actually perform the operation we want based on our schema. Each field on our schema is mirrored by a function with the same name in the resolvers. Let's see some examples of how this works in action. A now same index.qs file just above our server. I'm going to begin by creating our typeDefs. So const typeDefs, and this is going to be equal to a string which we use with the back ticks. So open this up. Once add these onto a new line just below this setup of a const of resolvers. Service this equal to an empty object for now. Let's begin by looking at the typeDefs, or the type definitions. When using GraphQL, we'll talk a lot about types. It's these types which describe our data. To begin, we have three root types, Query, Mutation, and Subscription. These types groups covered the operations we want to perform. Let's add these in now. So the first type, which is going to be Query, uppercase Q, and set this to an object. The second root type is going to be for Mutations, so type Mutation, capital M. The third one is going to be Subscription, type Subscription. Again, set this to an object. A query is used to query our server and get back the data we want. A mutation will send new data to the server. Finally, we have a subscription which gives us the real-time functionality, allowing the servers send data to the client once it changes. We'll be focusing on queries for this time though. So we can just delete the Mutation and Subscription for now, and we'll return back to these as we need them during the course. Query is created by first giving it a name, followed by a type, which we expect to get back. A basic example would look something like this. Would have a Query name of movie, and we expect to get back a string. We can add exclamation mark on the end, which is optional. This is to declare that we always want a screen back and it can never be the value of null. It can be empty if no data is found, but the returned value cannot contain a null value. The second part is to setup a resolver for this movie Query. Remember we said that each Query must have a resolver with a matching name. This resolver is responsible for actually performing the operation we want, in our case, to get a name of a movie. Just like the typeDefs, the resolvers take in a matching Query, Mutation, and Subscription object to group them together, but now though we just need the query. So inside the resolvers object, we can set up our Queries with a capital Q. Inside here, we can list all of our Queries and we'll just have one for now. So we can solve Query resolve method with a matching name of movie. Movie is going to be a function which is simply going to return a string. So return value, we can add any name we want. So the Lego movie is fine. This is going to return a string, since this is what we need for our Query just up above. If you're a little confused now, this is perfectly normal. I was too, when first learning all of this, since it's a little bit different from what we've used before. A lot of what we do for the rest of the course will follow this exact same pattern, so you'll get lots of practice. Now we can start up the server in the terminal and check if this working. Down to the bottom, inside the terminal, you can type in node, and then source, or /index.js. Remember, this is the entry point which we set earlier. Hit "Enter". Now we see the message of server is running on localhost 4000, which is the message we get back from our console log. Let's open up Chrome, type in localhost 4000. This will open up the Graph QL playground for us. Remember, GraphQL is a server or back end for our websites and applications. This GraphQL playground will allow us to interact with our service data when developing. Let's give this a go over on the left. Since this is a Query which we set up, we can type in Query followed by the curly braces. We only have one Query so far, which is movies. So we can now include this. You can see that the playground has a really good also completes, and it will try to suggest the names of our Queries and the fields as we go. Now if we go ahead and hit the play button in the middle on the right-hand side, we can see the movie data has been returned. We have the Query name of movie which we set, and also the string of text, which we said in the resolver. I'm now going to add another Query to get some more practice. This Query will be a user returning a type of string once more, and the resolver will return any username you choose. So starting with the typeDefs of above, you start the movie. We can add in our user colon. This is going to return a string, again, using the exclamation mark, meaning we don't want a value of null returned from the server. After this, we setup our resolver below. Just after the movie, we can add a comma, setup our user method, and then return a string value. I was to add my name inside here, gives us a safe over to Chrome. Now if we reload, and instead of movie we need user. You can see if we type in US, that the auto complete is not working. This is because when we make any changes at the moment, we need to restart our server. So back in its terminal, down on the bottom, control and C will close down the server. Then again we can run node, source, or /index.js. This will again restart our server. Reload the playgrounds. Now we can see the user type is also complete in a play and we get the returned user name. This is a first basic look at using Queries in GraphQL. Next, we will look at using some different types over the new string, and also how we can pass in arguments into our Queries.
7. Scalar Types & Passing in Arguments: In this video, we are going to be doing two main things. Number one, we discovered how to parse arguments into our queries. This will allow us to do so much more, including accessing the sample data we created earlier. Number two, so far we've only looked at the type of string. I want to show you what other types are also available. By default, GraphQL has five scalar types, which are available to describe our data. What are these in the comment at the top? The first one, which we already looked at is string. We also have a integer, a float, a boolean, and finally an ID. These types are pretty standard types in many programming languages, and nothing specific to GraphQL. An integer is a number without a decimal point. A float or a floating point number is a number which has a decimal place. A string, which we've already looked at, is a string or a sequence of characters, such as a letter, a word, or a sentence of texts. A boolean is a simple true or false value. Finally, an ID, which is a unique identifier, often used as a unique key for each item in our database. We'll make use of some of these in just a moment. Another thing which we'll be using often is passing arguments into our queries. Arguments work in the same way as passing arguments into a regular function. They provide some additional information which we can use. We add arguments in brackets just after the query name, like this. Our movie is our query name. Now we can pass in a title for this movie. Again, this has a type too, which you can set to be a string. This also has the exclamation mark, meaning the string is required and the count of the value of null returned. This means when we call the movie query from the GraphQL playgrounds, we will also be able to pass in the title null two. Well what happens we've this title when we pass in. Well, this is the job of the resolver to deal with it in any way which we want. To begin down in the resolvers with our movie, we include four parameters into our resolver method. These are parent, args, context, and also info. We will go into these in more detail throughout the course but for now, we'll be using args, which is short for arguments. This is how we can access these arguments, such as the movie title, which you pass in. Instead of returning a plain string, I'm going to use the backticks to return a template literal, which is just plain JavaScript, and say, my favorite movie is, followed by a space, and then need dollar symbol to inject our dynamic data. The data we want to inject into the string lives on the args property. This is called title, which matches the title which passed in as an argument. If you've not used template literals before, it involves using the backticks in place of the quotations. Then we can mix in plain text with a variable using these curly braces. Over to the GraphQL playground, we can now test this out. I've got the playground open in Chrome. You may need to restart the server. Close it down with Control C. Then run our server again with node, source, index.js. When this is running and we can refresh the GraphQL playgrounds, and we can test this out. We have the user still in from before. Now we need to change this to be a movie. We can now pass in our arguments inside of the brackets. Open and close the brackets. Then we can pass in our title, which again is a string. We can add any movie name inside here. We want to add a movie name there. Then hit the "Play" button. Now we'll see our completed string of my favorite movie is Wreck-It Ralph. But what if the user did not enter a title? Let's remove our string and then hit "Play" once more. We now just see the text entered of my favorite movie is. Well, this now looks a little silly, but the resolver is available to handle it in any way we want using JavaScript. We can add a JavaScript if statement inside of our resolver to first check if a title has been passed in. Inside of our movie, we could say if args.title. If this data exists, we can then cut our return statement, paste this inside the if statement. This will run if we have a title passed in. If not, we can say return 'Please enter your favorite movie...' Now save this. Control C to restart the server. Over to the playground, reload and now hit "Play". We now see the backup text of "Please enter your favorite movie". We can also add multiple arguments into the query too, which is a useful approach when querying for data, such as a user inside of our typedesk. If we go down to our user just here, open and close the brackets just afterwards. We can pass in a user ID and this is our first chance to look at a different scale type of ID. Again, we can use the exclamation mark because this is a required field which is going to return a value. We can add, separate by a comma, a second argument of name. This is going to be a string. We can add an email. This will also be a string too. Then down in our resolver method, we can pass in the same four parameters into our function. This is parent, args, CTX, which is short for context, and our info. Again, we don't need all four arguments are the moment. Well the sketch is in the habit of writing them so they become more familiar. Since we're passing in a user ID, name, and email, it would make sense to create a user object in a similar way to the users in our sample data. Would you see it just at the top here? So this is the same structure which we're going to create inside the resolver. First of all, we're going to create the user object based on the args. We can do this by setting up a constant with a name of the user and set this to be our object. We can set the ID just like in sample data then the name and the email. The ID is going to be from args.ID. The name is going to be args.name. Finally the email is going to be args.email. This ID, name, and email is also matching up with the args which are passing a bit just here. Back down, now instead returning our string, we're going to return this user object. Gives us a save, Control C to close down server and then restart our server. Back over to the playgrounds. We can reload this to get our information. Change this to be user. Inside of our user we add an ID. We can add in any ID we want here, I'm just going to go for "123456". The name, the email. Just make up any email inside here. Now we can hit "Play". When we hit "Play" now in the playground we see an error rather than the data which we expect to get back. The error message is, "String cannot represent a value" followed by our objects. You may have already noticed what the problem is here. If not, we can take look if we go back to our query. Will be in our query for the user, which is this line here. Right at the very end, we're returning back a string. But our user is structured as an object inside of our resolver. In the scalar types we looked at earlier. Look at the top, we can see the object is not one of the provided scalar types by GraphQL. This is fine though since GraphQL allows us to create a custom type called an object type. This is exactly what we'll be covering next.
8. Custom Object Types: We looked at the problem in the last video, that quite often the data we want back is not as simple as a string. This is where object types come into play. As they sound an object type is structured like an object and we can declare exactly what fields we get back from the server inside of our type tasks, which we have here. Outside of this root query type, we can set up a new customer object type of user. Add the type user and then open and close the curly braces, making sure this is still inside of the bactics. This user type can contain any structure which we want. In our case, we wanted to mirror the user structure you used before by adding the ID, name, and email fields. First of all, we use the ID, which is a type of ID. We pass in a name, which is going to be a string. Then we're going to pass in the email, which again is a type of string. Now in our query just above, rather than returning a string for the user, we can now return our user objects. Again, we can add the exclamation mark saying we don't want to return any null values. Give this a Save, goes down the server and then restart. If we have no errors. We can now go back over to the graphql playgrounds. If you still have the user query open, we can refresh and then hit play using the same query. This time we don't get the error which we had before. Instead, the error message is type user must have a selection of sub-fields. This just means we need to tell the server what fields we want to get back from his query. Just after we user query, we can also add in some curly braces. Open and close these never can declare which of our three fields we want to get back. I'm goes to add to the ID, I'm going to add the user's name and also the email too. We can then send this query off again by pressing play or command or control enter. This will now return our user data as an object with the ID, name, and email, which we specify inside of here. We can return any amounts of these fields. We don't have to return all free. This is one of the benefits of using graphql. We can get back only the exact data we want. We have traditional APIs, we could get back all of the data even if it's not required. I'm now going to do one more objective type for our movie. I would encourage you to give this a go first before following along, we will first create an object type called movie just like we did for the user just hear. With the fields inside of ID and tittle. Then modify our query just above to return this new type rather than a string. Let's begin just on the user. This is going to be a type of movie. As mentioned before this is going to have the ID as the field, with the ID as the you return value and then also a title field, which will return a string. Then the move resolver just above, instead of returning a string, we want to return the object we just created, which is moving. Also add in our second arguments of ID, which is going to return the type of ID and separate these with a comma. Moving down to the movie resolver, we can also create an object with this ID and title. Let's remove the statement from before. Then we can create our constants called movie service. This opt to be our object, which has the ID. I'm going to grab the ID from args dot ID separated by comma, the title. But you also ground from args, so title and then we can replace our return string with the movie object we just created. Okay, so now back down to the terminal, control c to closer down and then restart. The playgrounds, we can reload this and we can test this out now inside the playgrounds. I'm going to open up a new tab. Let's query for our movie. Inside the movie, we can pass in the ID. Any ID is fine. I'm going to add one, two, three. Then next we can pass it in the second argument, which is the title of the movie. I'm going to add the Secret Life of Pets. Just like before if we go ahead and play this, we'll now tell when we need a selection of sub-fields from our movie, the sub-fields will have the option of ID title so on one's out, both of these inside here, then hit play and we'll now return with the movie data, with the ID and also the title. Using these custom object types allows us to have a lot of flexibility over how we want our data to look and behave. I will make use of these custom types a lot more as we go for the rest of the course.
9. Working with the Context and Arrays: Earlier in the course, we added some sample data to work with. This will act as our temporary database until we add a real one in a later section. Over in our project, in our index.js file, we included our sample data up at the top, on this line of coaches here. We start at the Users, the Movies and the Reviews into their own variables, and then down at the bottom of the file, we will create a resolver, we created a Context Object, which is just here. Then we passed our three variables inside, and this is how we can use our sample data in the projects. Anything we'll pass into the context will be available to all resolvers. To begin, I'm going to set up a new query to get all of the movies from our sample data. So up in our typeDefs, and the Query section, we want to setup a movies query. This movie's query doesn't need to take in any arguments. So we can just return a type of movie. Remember the movie type is a custom object we created earlier on. However, this approach is only partially correct. Yes, we want a movie type returned, but we want an array of movies not just one. In graphQL, we can wrap our movie type in square brackets to declare we want this to be an array of movies. This array can also be non-nullable too. So adding an exclamation mark just after means we can always expect an array back. We have zero or more items and not a null value. An exclamation mark after movie can still also be used too just like we have here. Meaning we always expect to get back a movie object and not a value of null. As with all of the queries a resolver with the same name is required, that is the function. So scroll down. After our movie, we can also create movies. This also takes in the same four parameters. We have parent, args, context, and info, and then add a comma right at the very end to separate this from our user. The purpose of this resolver is to fetch the movies from our sample data which were added to the context below just here. We can access the context in our resolvers by using this context parameter of ctx. So inside of here, we can return ctx followed by the name of the context, which is movies. Back down to the terminal, we can restart our server. Once this is running, we can go over to the graphQL playground, restart, and then we can create our query. So Query, and we want to query for the movies. This doesn't take in any arguments, but since it's a object type, we want to return some fields. I'm going to return the ID and the movie title, and then send off this data. The title return is the free movies from the movies array in our sample data. Back over to the queries, we can also remove our user query, which is this line just here as this is no longer needed for the project. In place, we're going to search for the users, this is going to return an array of the user type, and then down we can create the matching resolver, which is going to be responsible for getting all of the users from our sample data. So we can modify user, and it changes to be users instead of returning the user objects, we're going to return our users array from the context. So users, and it's return from ctx.users. Once more we can restart the server, go over to the playground, and in fact, it's opened up a new query of users. Again no arguments are passed in, we just need to return the ID, and in fact we may need to reload this, so the ID. We also have the name and the user also has an email. Then we've got all of the users from our sample data. The final data we need to get from the context is the reviews. Again, I would encourage you to try this on your own if you feel confident doing so, just remember we have not yet set up a Custom Object Type for the review, so we also need to do this for this query to work. So this is what I'm going to go ahead and do now. We can start in the typeDef's, just after the users and movies. We can create a new type, which is review. This review is going to have an ID, a correspondent movie, the review text, and also the rating, which mirrors our sample data. So our object would look very similar to this. We won't be adding the User field just yet. We'll add this at a later date, when we create a relationship between the reviews and the user. So back over to our review type. The ID is the type of ID, the movie. For now we're going to add this as a string. Since this is saved as a string in the reviews. Next up we have the review text. This is a type of string too, and then finally the rating, which is a type of integer, and then we set up the Review Query. So scroll up to our Query section here. We can add in the Reviews Query. Just like before this is going to take in an array of the review type. Now we can create the matching resolver just after users. This one is called reviews, which will take in the same four parameters of parent, args, the context, and info. Inside here, all we need to do is to return the context.reviews to get our sample data. Okay, good. We can now restart the server, head over to the graphQL playground. We can remove the User Query and in place we can add our Query Type for the reviews. This isn't taking any arguments like the last two, all we need to do is to return the data we want. So I'm going to add the ID, the movie, the review text, and also the rating. Send this off. Now we get an array of reviews from our sample data. We've now set up our work in operations to get our users movies and reviews. Later in the course, we will replace this sample data with a real database. Although this may seem complex at first for each now we've seen that most of it follows a similar pattern. Next, we going to make a small change to our project, that automatically restart our server each time we make a change.
10. Automatically Restarting the Server: This is just going to be a quick video to install a npm package called nodemon. At the moment, each time we make a change to our files, we need to close down and restart our server. Nodemon will save us doing this by automatically restarting the server photos when we save a file. Nodemon is available for more information at nodemon.io, but I'm going to go ahead and install this over in the terminal. Let's close down our server. Then we can add a npm install, --save-dev and then the package name of nodemon. Hit "Enter". This will pull in the package from npm. The save-dev will save this inside of our package.json as a dev dependency, meaning this will save this as a dependency only during development. Good. Once this is installed, we can then check this out over in the cyber and the package.json and check. This is saved as a development only dependency. In the same file, scrolling up, we have a script section just here. We can add a new start scripts to now take advantage of nodemon. We can add "Start" inside of the quotations followed by a colon. Npm start will run the command which we type next. So, between the quotations, I'm going to add nodemon and then the file path to our server, which is src/index.js. Add a comma just after this to separate this from our test script and then we can give this file a safe. This is similar to the command we run before in the terminal to start the server. But now, we replace node with nodemon. Now, we can try this out. Down in the terminal, we can run npm, start and hit "Enter." This then runs the script we specified which is nodemon src/index.js. Again, we see the server is running on localhost port 4,000. Now, if we go into any of our files in our project and hit "Save," keep an eye on the terminal at the bottom. We now see that the server restarts, meaning we don't need to manually close down the server and restart it after each change. This is all we need to do for this to work. Next, we'll refactor our code to keep things more organized.
11. Refactoring our Code: Even at this early stage of our project, we can see that by having everything in the index.js file that thing is again a little crowded. I'm going to not take a few moments to remove our typeDefs of schema, and also the resolvers out this file and organize them into separate files. Starting with our typeDefs, where chrony we use the back ticks to create all of our type definitions inside. We can also take these out of here and place them into a separate GraphQL file. I'm going to create this file inside of the source folder and call this the Schema.graphql. We can then go back to our index and cut all of our type definitions out of here. Cut everything except the back ticks. From the type of review, all the way up to our query, cut this out. Then paste it into our schema.graphql. Back over in the index.js, we can delete the typeDefs string, which we have here and also our comment from above. Scrolling down to our server, we now need to modify our type definitions to reflect this. We can point the typeDefs now to the location of our new file. The typeDefs now going to be equal to a string. This is going to be dot slash. We use the source folder and the file was schema.graphql. Save the file and at this stage you should maybe now go off the playground and check things still working. Our server has automatically restarted using nodemon, so now we can refresh the playgrounds. Then we can reload our queries and check if we get back all of the data we want rather than any errors. This all seems to be working fine. The next step is to move the resolvers into a new file 2. Again, in the source directory, I'm going to create a new file called resolvers with the dot js extension. Over to the index.js, we can grab all of our resolvers object. Let's grab everything including the const name. Cut from the closing curly brace all the way up. Take these out of our index file, paste them in the resolvers file. Then down on the bottom of the file, we need to export this resolvers object, for this to work. We exposed our file with module.exports and set this equal to our name of resolvers, which is the name of our object up at the top just here. Now we've exported this file, we can now use this again in our index.js backup in our index file. Unlike our type definitions, where we can pass in a file directly, just like we have here. We need to require this file at the top. We'll create a new constant called resolvers and set this to our file path. So we can require the file path as a string, which is dot slash resolvers. This const name of resolvers also matches the name we've passed into the server, which is just here. We don't need to make any more changes. The final thing I want to do to refactor our code is to remove the movie query. We no longer need this for our projects. So we can go over to our schema inside of our query object, removes the first line of movie. Also in the resolvers, we can remove the matching resolver. Let's find the movie, we can remove all of this from our query section, say this file. This was just for demonstration purposes early in the course. I'll no longer need this for our project. All that's left to do is to go back over to the GraphQL playgrounds and test if things are still working. So refresh. We can try clicking on some of these queries. We still seem to get the required data back. With all of this now taken care of and our code is more organized. Now we can go back to GraphQL, and discovering how we can set up relationships between types.
12. Relationships Between Types: By now we should be getting a better understanding about how GraphQL uses types. But we'll soon come to find that often. We need to setup links or relationships between these types. Even though we are only in the early stages of our project, we already have the need to setup relationships. The slide is the free custom object types we have in our projects at the moment they are all independent of each other but this is not how it should be. We have users which will be responsible for posting reviews, so we need setup a relationship between the user and the review type and we can do this by adding a review's field to the user. As we see here, this will be an array of reviews since a user could post as many reviews as they wanted. Below this, we also have the movie type and this will also need the same reviews relationship to. Since review in a movie is a whole point of this project, we can add in the reviews fields, and this is also an array since we can have multiple reviews for the same movie. For the review type, this will also need a relationship to both the user who created it and also the movie it is based on. We will need to do two things for this review type. First of all, we need to change the movie field from a string value to a movie, a single movie, not an array and finally, setup a user field, so we will know which user created this review. Now we have a clear idea of how we can set up our relationships. Let's now move on to implement the changes in the next video.
13. Creating Our Relationships Part 1: Now let's get to work creating the relationships for our review type. As we already looked at, this involves two fields. When it changed the movie field to return a movie rather than a string and a new field for the user who created it. Let's go back over to the schema.graphql in our project. In our schema file, we can do this one field at a time. Scroll down to the review type and first we need to change the movie field, return a movie rather than a string. This will allow us when query and reviews and also pulling all of the movie data it is for and now there's one more step we need to take at the moment, each time the resolver files for this type of review, it can resolve all of this fields with scalar values without any problems. Since we're just returning a string, an integer, or an id for example however, when querying for this review and we find a movie type, which is a custom object type. We also need to setup a separate resolver, so GraphQL can loop through all of the movies which match and find the correct one to return back. If we don't create this resolver GraphQL has no way of knowing exactly which movie we want to find. Save this file and then we can go over to the GraphQL playground and we can try to add in our movie data to be included. If we refresh the reviews query, hit play, we see the movie type. Now this is no longer a string, must have a selection of sub-fields. We can easily add this in with the curly braces and add in the movie id and title too. How am I get an error message saying, "We cannot return null for a non null-able field" which is related to the movie. This is because we have not yet created this resolver mentioned before to get the correct movie data over in the resolvers.jsfile, we can create this now. We need to create this as a new property, which is called review to match our review type. Down just after query, add a comma and then add the route review type and then settled by method, just like we've done previously but the method name must match the field from this review type. In our case, this is movie. This also takes in the same for parameters of parents, args, context and info. The responsibility of this resolver is to loop through all of the movies in our sample data and find the one with the id from our review. We can do this by using the JavaScript find method. We can add a return value, so context, we're going to loop through all the movies. Where did the JavaScript find method? Each movie finds inside this loop will be stored in the variable name of movie. This find method, which is just regular JavaScript will run this function for each item in the array. Each item from the movie array is installed inside of this movie variable, which we suggest here. It will return through if the movie id from our sample data. Return the movie.id matches the movie id from the review. But how do we access the movie id from the review? We access this using a parameter we have not used yet, which is this parents just here, followed by the field name of movie. We can check if this is equal to parent.movie. In this case, movies are a child of the reviews type. The parent refers to the resolver one level up. To understand how this works better, let's take a look at what's happening in our schema. Looking at our review type, this as we know has a much in resolver. If resolver can resolve the values of id, review text and also rating immediately because this are all scalar types. However, with this movie type here, it won't know immediately which movie to return so we then run this separate resolver, which we just created called movie. This movie resolver is nested inside of the review and this is why we have to use the parents to get data from the review type. This may seem a little confusing at first, but we'll look at a few more examples of this, which should help. Now if we save this file ahead over to the GraphQL playground, we can rerun the reviews query, refresh the playgrounds, hit "Play." Now we found the corresponding movie data for each review which has been linked by the ids. Let's do this again, but this time adding a user to review. Over in the schema.graphql, first we add a user field to the review type. Down at the bottom, a new user field, which is going to return a custom object type of user over in the sample data. If we go to the reviews, you can see we already have a user type on here, which is linked to an id of the user so 1002, 1001 and this all use the ids from the top. Now we need to create the resolver for this user field and the job of this resolver is to match up this ids. This resolver will follow a similar pattern to the last one over in the resolvers file. This user field can also be added to the same review type so we can add this just after the movie, add a comma, the field name of user, which also takes in the parents, the args, the context and also the info. Inside here we want to add a return value, which you're going to look up the context and the users array. This is also going to use the JavaScript find method to loop through every item on the array and store in a value called user. For each user which is returned from the array, we're going to return through if the user id is equal to parents.user. User id will be the field from our sample data, raw particularly user. The parents.user will be the id down in our reviews from this user field just here. Back over in the playground for save this file, head over and reload the reviews we can also add our user to the selection. The user, this is also an object so we can add in some fields. Let's just go for the name and then hit "Enter." Now for each review inside of our sample data, we've looked up the movie and pulled in the id and title. I have also found the match in user from our sample data by the id. This is all the relationships we now need for the review type. We will continue to get small practice with relationships in the next video, where we will link both the user and the movie type to the reviews.
14. Creating Our Relationships Part 2: Factorial slide from before. We still have the two relationships On the left-hand side setup. We need to link the user to a review, this will allow us to query for users and also see the reviews which they've made. Also down below, the same reviews field for the movie Type 2. This will allow us to query for movies and then see the reviews for each one. Both of these relationships follow the same person from the last video, we add a new field called reviews and then create a resolver to fetch the data between it. Again, we add these new fields over in our schema. Let's begin with the type of user. Just at the very bottom, I'm going to create a new reviews fields and this is going to be an array of the review type. Since the user can place multiple reviews, this needs to be an array. Next, we need to set up a corresponding resolver to match the user ID. What we're going to do if we take a look at the sample data? If we go down to reviews inside of the resolver, will going to loop through all of the reviews using JavaScript, and then find the user ID for each one. This is going to be accessed with reviews or user, we're then going to check if this is equal to the parents which is our user.id. Once you have a much, this will return true and then provides the information we need. Now, we can save our schema and then go over to the resolvers, and create this resolver for the user type called reviews. We've finished with the resolvers for the review type, let's go to the end of this and then create a new property called user. This will be a object. Since as you know from before we can add multiple resolvers inside here. We only need reviews at the moment, let's add the method name of reviews. Take in the parents, the args, the context, and the info. Then similar to of above, we're going to use a method and rather than using the find method, we're going to use the filter method, since we can return multiple values or multiple reviews. Let's return the context.reviews.filter. Again, this is just plain JavaScript, we're going to filter through all of the reviews and then setup our function. Each item in the reviews is going to be stored in this review variable. What do we want to do here? Well, just like we looked at in the sample data, we want to match the review.user. If you scroll down this field just here, now we want to match it with a user ID. We can grab the user by checking if this is equal to the parents.id. Great. Now, give this a save and then head over to the playground. We can go to our users query, refresh, when all this is working because we haven't added the new field yet. With just have the email, we can also add in reviews, inside the reviews we also need to add in the fields which wants to get back. Let's add the review text and the rate in and this all works fine. When getting back this information, we probably want to get the movie title to, so know which movie this review is for. We can nest this inside of reviews, so we can access movie and then the fields which we want to get back? I'm just going to add the title and then nested inside, we also get this title for each review. How do you know this movie will work when nested inside of reviews? Well, this is because you've already setup the resolver for this in the last video. When returning a review movie is a property on the review type. Back in our schema, we can see this if we go down to our review type, we have the movie then we have a corresponding resolver to fetches movie over in the resolvers.js, and there is this method just here. Now, things are starting to tie in together. I will now form in relationships between our types. With this in place, we just have one final relationship to add in and that is to also add the same reviews field to the movie type. If you feel confident, go ahead and give this a go on your own, it will get you thinking about how things all fit together, and you can also follow along with me afterwards. Let's begin with the movie type in the schema. We're going to add the same reviews fields. Just after the title, this is also going to return the type of array. Since the movie can have multiple reviews, for simplicity at this stage in the sample data, I've just added a single review rather than an array of multiple reviews but we'll deal with multiple reviews later when using PRISMA. Over to the resolvers, we set up our movie type on the route. Save this file, we have our reviews, we have our user resolvers, and then next we also need setup our move resolvers and this is an object and then we add the property name. This is the reviews, just like above us in the four parameters. This is also going to return a filter overviews. Return ctx.reviews.filter and we setup our function. Inside here, we're going to add a return value. Just like above we're going to to return the review, but this time we want to target the ID. If we go over to our sample data and down to the reviews, we're going to grab a review by it's ID, and then we're going to check if this is equal to parents.reviews. Parents will point to the movies and then the ID stored on reviews. Once we get a match between these two values, we'll then return true each item in our array. Back in resolvers, let's finish this off, check if this is equal to parent.reviews, give this a save and then over to the playground, we need to go for the query for the movies. Let's reload the browser. After the title, we can pass in the reviews, we can get the review text, the rating, and we can also check which user has posted this review as access the user type, and we get the user name, hit Enter and now see our view has been returned for each movie. We also have the corresponding user. Again, since we set up a user's resolver for the reviews, we did this in our schema. If we go to our review type, we also set up this resolver to grab the required user. Great. With all of these now working correctly, this is all our relationships now in place.
15. Introduction to Mutations: In the last section, we mainly focused on getting data back, which was already there by using queries. This was from our sample data. Which will soon be a real database. Now we're going to switch things around and send the new data, back to our database. These are called mutations and they can send anything which you want, such as a new user, a new movie, or a new review. Mutations follow a similar pattern to the queries which you've already used. We setup the mutations we want in the schema, declaring what type of data we want to get back. Then these also have a much in resolver too. One resolver per mutation. To begin, we can add a new root mutation property to our schema currently we have the type, so let's add the second root property of mutation again as an object, so we can group all of our mutations together. We briefly looked at this earlier when setting up the type devs. This is one of the three root properties. The third one is subscription, which will also cover soon. Then as we did with the queries above, we add the name of our mutation, followed by the type we want returned. I'm going to create a signup mutation, signup a user, which is going to return the user type, capital U. This can return any of the same scale of types, such as the string, a Boolean, or also our custom object types, such as this user. When signing of the user, it's not much use if we can't pass in any data about the user, and again, we can do this easily by passing in arguments. Let's go ahead and add the brackets after signup. We can add a username, which will be a type of string separated by comma, an email, also with the type of string, you may notice we're only passing in two arguments to this mutation for the user. But if we scroll down below to the user type, this user has four fields. Well, this is because the ID will be also generated by Prisma later in the course, and it's not something which we would expect the user to provide, since it needs to be unique. Since the reviews have a custom object type, they can have their own resolver to fetch the required data. [inaudible] the resolvers for each mutation. Save this file and then go out to the resolvers. Mutation is also a root property, so I'm going to add this after query. Find the closing brace, which is just above review, can add mutation, save as an object and add a comma, separate this from reviews. This is an object which takes in one method or one resolver for each mutation. The only mutation we have is called signup, and this also takes in the same four arguments as when creating a query, so this is parents, args, context and info, and then the curly braces. The user type is an object, so we need to also create a user object to match the structure. Const, user, and we can set this equal to an object. The first field is the ID, and this will be also generated by Prisma later, but for now we need to create one to store in our sample data. If we go over to our sample data and then go and take a look at the user object, each ID begins at 1,000, so we have 1,001, 1,002, and 1,003, so we can match this pattern in the user object. Again, don't worry too much about what we're doing here, this is just to generate a temporary ID until we use Prisma later. We can create the ID, is going to be a template string, so we can use the back ticks. We want the ID to begin with one double zero, and then we want this to increment by one for each user in our array. We can then make the fourth digit dynamic by passing it in using JavaScript. We're going to loop through the users array with ctx.users, and then grab the length of the array. Currently we have three users inside of our sample data. I'm going to increase this by one with each user we're going to add. Add a comma on the end there and then we can go ahead and add the next two fields, which are more straightforward. We can grab the name and email from the args as we've already seen when using queries. The name is going to be args.name. The email, args.email, and then we can go ahead and push this new user to our users array. Grab the context.users. We can then use a JavaScript array method to push this user to our sample data. This push method is just regular JavaScript and nothing specific to GraphQL. Finally, we can then return the new user on the next line. Just like queries, we can also test out our mutations in the GraphQL playground. This time I'm going to open up a new tab. This is the type of mutation, so we set this up like this, and then we can add our signup inside. In fact we will need to refresh. Now that it's also complete, so signup. Signup is going to take in the arguments. First of all we have the name, so let's add a name inside here, and also the second one was email. User, both strings. You can add any data you want inside of here for the user. This is also going to return a type of user. We need to grab the ID, the name, and we can also grab the email too, run this. Now our signup has successfully run, we have the ID, the name, and the email. We see the ID has been increased by the value of one. If we hit "Enter" again, you see 1,005 and again 1,006, so this increases by one for each item in the array. Let's rerun our users query and check that these extra users have been added. Scroll down, we'll have our free from sample data, and then we have the ones we just added in just then. Since we're not using a permanent database just yet, any changes you make to the sample data will just be stored in memory, making them temporary. We can restart the server by saving any file, so Command or Control S. Back to the playground. Let's reload and we can rerun the users query. Now scrolling down, we just see the ones that are stored in our sample data and not the ones we just added from our mutation. In real-world applications, the name and email arguments would be provided from the frontend, such as a website's signup or login page. But since the GraphQL is for the backend, we've tested things out in this playground, and that is everything we need to do so we can send data to our server. Next, we will look at adding a few more mutations which we'll need in our projects.
16. Movie and Review Mutations: Now we've looked at how mutations work. Let's now add two more. One to create a review, and one to create a new movie. Starting in schema with the Create Movie mutation. Back over to our project, and the schema.graphql. We're going to use the same mutation objects we used for the sign-up before. On the new line, I'm going to call this createMovie. This createMovie is also going to take in some arguments. In fact, this will be a single argument of title, which is going to be of type string. We also need to set the return value, which is going to be our custom type of movie. Over to the resolvers file, we can create the matching resolver inside this mutation object. Just after sign-up, separate this with a comma, createMovie, taking in the parents, the familiar args, context, and info. Following a similar pattern to the user sign-up, we're going to create a movie objects. This is also going to have an Id and a title, and once more we need to increments the Id by one each time by checking how many movies are inside of the sample data and then increasing it by one in each addition. The sample data we should go down to the movies, we're going to generate the ID and also the title. But currently we are going to leave the reviews empty as this will be linked with Prisma later on. Let's go ahead and create our object const movie. This is going to be equal to our ID property. Then create the backticks to make this a template literal. All of the IDs for our movies in the sample data begin with 200, 2001 and 2002. Let's begin with 200, and then we're going to add onto the end the value from context.movies.length and then increase this array length by one for each addition, separate by a comma. Next we need to add the title, which is much simpler, we can grab this off the args. Just like the user above, we also then need to push this to the array ctx.movies, the JavaScript push method, and then I'm going to push our movie object. The last thing to do is to return this movie from this method, and then we're good to go. Over to the Playground, let's test this out. Reload. We don't have this mutation just yet, for creating movie, so let's add this to a new tab. Create movie. This takes in a single argument of title, and I'm going to add a movie name of The Secret Life Of Pets. Just like that, and then we can return our values for the movie. Let's add the ID and also a title, and then run this, and that seems to be working okay. We have our data now returned on the right. We can double check this is working by fetching all the movies from our query. Let's run this, and down at the bottom we have our new movie of The Secret Life Of Pets. Great. Next we can complete our final mutation and that is to create a new review. As always, we begin by setting up the mutation in our schema. To the schema.graphql we can add a first mutation, which is to create review. This is going to get back the type of review and it's required. We also need to pass in the information for our review by the arguments. I'm going to add these onto a new line since it's going to be for different ones. Since this review is going to be for a particular movie, we need to link this by adding a movie ID, which is a scalar type of ID. We also need to add the text for the review. I'm going to add this as review text, which is a type of string. We also need to add a rating, which is a type of integer, and then we also need to link this review to the user which we created it by adding a user ID field. This can also return an ID, and this is everything we need to create a review. Then our matching resolver just after createMovie, add a comma at the end and we can create our resolver for create review, following a similar pattern, so parents, args, context, and info. Then we set up our constant of review, which is going to be our object, which we'll construct. In a sample data if we look at the reviews at the end, we see the ID begins with 300. Just like the two methods above, we're going to setup our ID property and then increment this by one each time. Let's start with 300. We can then get the length of the reviews array with ctx.reviews.length plus one. The next property we need is for the movie. We can grab this with args.movieId. Next we have the review text. This is args.reviewText. The next one is for the rating, and this is from the args again, so args.rating. The final one is to link this review to a user, and we can grab this from the args.userId. Just after this object, we do our two familiar things. First of all, we need to push this to the reviews object with ctx.reviews.push, adding in our review object, and then finally, we need to return this review from our method. In a real application, we want to restrict the rating to a particular value, say between zero and five. But this is fine for the moment since we just learned about GraphQL. Give this file a save and then over to the Playground, we can test this out. Reload the browser, open up a new tab with the type of mutation, and the name for this was Create Review. I'm going to add this on a new line since these multiple arguments start in. The first one was a movie ID, and since we want to test if this is really working, we're going to grab a real movie ID. From our sample data, let's grab 2002, and add this in. On the next line is the review text. This is a string, so we can add anything into here, separate it by a comma. The next line is for the rating. I'm going to give this a value of five, and then finally the user ID, and this again needs to match a real ID inside of our sample data. Let's say User 1 created this one. Copy 1001, add this in. Just after this brackets, we also need to add in the curly braces to declare what fields we want to get back, the review we want to get back in our ID. We can also get back a movie title. So movie, and then one of the returned fields is going to be the title, and then back to our normal review fields, so it's the review text. We can also grab the rating, and then finally, we can also grab the user which created this. For the user we also need to get back a selection set of fields. I'm just going to go for the name. Let's test this out. We got a message "Expected type Int; found five". This just needs to be without the quotations. Rerun this, and we have a successfully created review, which is also linked to the movie and also to the user. Because of the resolvers we created earlier for these types, let's now test the query for reviews. We can rerun this. Let's scroll down to the bottom, and we have the review which we just created. This means all of our mutations are now working. We can create users, movies, and reviews. We also get back all of the exact data we want from each.
17. Subscriptions: Early in the course, we mentioned that our type graphs have re-root types. These types are Query, Mutation and Subscription. We've already covered the first two already. Now we're going to take a look at how subscriptions work. Like a query, subscription is a way to get the data we want. However, one of the drawbacks of a query is we don't always know if the data has changed since we got it back. If we want to be sure, we have to keep making the same query as many times as needed. This is not a very efficient way of doing things. This is why subscriptions come into play. We can subscribe to some data. Each time that data changes, the new data is sent to a client, whether that client is a website or a mobile device, or even the GraphQL playground. It does this by using Web sockets to keep an open connection with the client. What this will do for our project is it will allow us to subscribe to the movie reviews. Each time a new review is posted, we will then be notified. In a real-world application, this could be linked to a user to inform them when a new review has been made on a move they have liked, or even just to pop up a new review on a webpage as they are posted. Graphql-yoga also comes with support for subscriptions, so we don't even need to install anything extra to get started. These are setup in our project using a similar pattern to the queries and mutations. We set up the subscription on the root of our schema in our schema.graphql file, and also a matching resolver for each subscription we create. So let's begin in the schema where we set up the subscription site. So just after Query and Mutation, I'd set this up on the route. So type Subscription, open up the curly braces in. Over here we follow the same pattern as queries and mutations by given our subscription a name. So I'm going to give this a name of review, followed by the type we want returned, which is a custom object type. Save this file, and then over in the resolvers, we need to setup the subscription object. So I'm going to do this after Query and Mutation. Let's add this in. So Subscription, capital S, so it's our object, and then add a comma at the very end. As always, the resolver must have a matching name. In our case, this is review. Then inside of this review object, we use a subscribe method. The subscribe method also takes in the parent, the argsm, the context, and also the info. When working with subscriptions, we use what is called a publish subscribe pattern, often shown to pubsub. Publisher is the sender of the message and subscriber will be our application. We can set up a new pub-sub instance by first importing this from the GraphQL yoga module, and we do this in the index.js. We already grabbing the GraphQL server from the yoga package. So let's also grab PubSub. Then we need to create a new PubSub instance, which I'm going to do just before the server. Const, we'll observe, and this is going to be equal to a new PubSub instance just like this. This will allow us to implement PubSup into our projects, and we can do this by adding PubSub to the context below. So inside is context object right at the very bottom, we can add our instance of PubSub, so this is available in all of the resolvers. By going to our resolvable can now finish this off. Inside of the subscribe method, we need to return something from PubSub. So we can return ctx.pubsub. What we want to return is a asyncIterator method. So pubsub.asyncIterator. This asyncIterator is responsible for pushing back the data to the subscribe client. We subscribed to this by adding a channel name of our choice, which I'm going to call mine new review. So inside here has a string. We add a channel name of new review, capital R and you can call this anything you want. So now we have asyncIterator which will return any new reviews. The next step is to go up to the create review mutation just above, which is this one just here. Here when a new review is created using this resolver, we can also publish this data to the new review channel. We do this again by accessing PubSub from the context. Let's do it just before we return our review. So ctx.pubsub, and then we can call a method on pubsub called Publish. Inside of this method, we first pass in the channel name as a string. Just to match the channel name from here, we're going to use newReview. Then after they're separated by comma, we pass in an object containing the data which you want to publish, which is our review object from above. So let's add an object and the name of review, which matches this review object just here. This review must match the return type from our schema. In our schema.graphql, if we go to our subscription, here we're returning a type of review. This is exactly what we're publishing so things match up. Subscriptions can also be tested in the playground, so let's head over to the web browser and then reload. Let's create a new tab for subscription with a similar structure to we've already used for queries and mutations. The subscription name is review, and we're going to return back a type of review, including an ID, a rating, and also the review text. If we hit play, we see at the bottom we get a message of listening, and he spinner in the middle. This is listening for any new data published to our channel, which is when a new review is made. We can test this out by adding a new review. So let's say the movie this time is 2003. The user is 1003. Let's just say new review inside here, send this off and the review is created. Back to our subscription, great, our new review is now shown up in the subscription. Let's just create one more, over 2002, new review 2 send this off, and our second review is now being shown. We can also use the subscriptions to pull in any of the data we want from the server too by creating different channels. They can be set up in the exact same way as we have just done for reviews.
18. Prisma Setup: We now get to an exciting part of the course where we get to implement a real working database in place of our sample data. To do this, we'll be using a service called Prisma, which is available from prisma.io. You can think of Prisma as the link between our GraphQL resolvers and the database. It sits between our database and the GraphQL server creating the link. It will allow us to perform CRUD operations on our database, so we can create, read, update, and delete data along with working with real-time data too. We do this by updating our resolvers to include Prisma methods for interacting with our database in place of what we're currently doing, which is pushing and reading from our sample data file. Prisma is compatible with lots of popular databases such as MySQL, Postgre and MongoDB. It also models our data so we can structure how our data should look. If you've used something such as Mongoose before, it does a similar job to this. However, Prisma is more tailored to working with the flexibility of GraphQL and even comes with a free hosted demo database to try things out, and we'll set this up in a few moments. To begin, I'm going to install the Prisma CLI globally from the terminal. Let's go back to VS code, inside this terminal, we can run npm i -g, and this -g flank will install this globally and we want to install the package name of Prisma and let this pull in the Prisma package from npm. The Prisma CLI is a tool used to manage and deploy our Prisma services, we'll be using some of the commands which it provides, such as the init command to set up our projects. Let's run this now, so prisma init followed by the folder name which you want to add, all of our Prisma files and folders inside in what's called mime Prisma and then hit Enter. This will set off our initialization where we can choose the database we want to use, we can use an existing database if we already have one, we can create a new local database using a docker container, or I'm going to choose the demo server, which is a free development environment hosted by Prisma, select this and then we have the choice of regions, I'm going to select the closest one to me, hit Enter. We can select a name for our service, I want to call mine the movie review database, hit Enter and then the development stage. Next, we can select the language of the Prisma clients we want to use, I'm going to be using JavaScript, so I'm going to select the Prisma JavaScript clients. The Prisma client is an auto generated library which provides all the operations we need when working with our database and these operations are based off a data model, which we'll take a look at soon. We've created a folder called Prisma, which is in the root of our directory here, so now I'm going to use CD to change into the Prisma folder and then we can deploy our new Prisma service using the Prisma deploy command. Add Prisma deploy in the terminal, I've hit Enter. Just give this a few moment to run. If we scroll up to make some more space, we can see our service has been deployed and we can also see we've created a user type and we'll take a look why this is in just a moment and then scrolling down, we have some links on here, if we open this up, let's copy this link, this will open up the playground which is linked to Prisma and then add this inside the browser, this will open up a new instance of the GraphQL playgrounds. Further down, we also have the link for our database, so we can copy this, go back over to Chrome and then we can paste this in as a new tab. This is the user interface for our demo database, we can see on the left-hand side, we have a type of user and we don't have any records inserted just yet, so you may be wondering why we have only this type of user or we don't see any reference to our reviews or movies. Well, this is because of a file called data model. If we open up the sidebar, go into the Prisma folder which has been created, we have a file called data model dot Prisma. This data model looks like the schema we already have and Prisma is set to open a default user type. This is the file which we'll use to structure all of our types we want to save to the database. This file will reflect how our database tables will be. Since we only have the user type, this is why we only see the user type inside of the demo database. One of the difficult things to understand when first looking at all of this is why do we have to create our types in both this file and also the schema dot GraphQL. Well, there is cases when these two files will look a little different, the data model, which just has our user, will describe what we want to save to the database whereas the schema will describe what data is available to the client to use. An example of when these files will look different is a typical user type. We would often want a password field for the user to be stored in the database but we may not want to add a password field in our schema, therefore, exposing this to the client as this may pose a security risk. Also, since our data model is only responsible for structuring and shaping our data, it also doesn't contain any of the queries or mutations which we have defined in our schema. So, just a recap, our schema provides all the information for our front-end or for our clients and the data model reflects everything we see here in this database. Back over in our project, also inside of this Prisma folder, we have a generated folder, if we open this up, we have a file inside called Prisma-schema dot js. If we take a look inside, this file contains a lot of code which has been also generated by Prisma. The Prisma client has generated all this based off the single user type, which we have in our data model. You will see for example, mutations have been setup all based on the user, such as create user, update user, and delete user. Now, all of these actions will be available for us to use in the resolvers and this is one of the real benefits when using Prisma. Each time we add something new to our data model, we need to regenerate this file and we'll look at how to do this soon. Another file added when we run Prisma init, was the Prisma dot yml file. If we open this up, it makes more space. This is a Prisma config file which holds the database endpoints at the top, which points to our demo database we just looked at before. This can also be used for the databases too and then below this, we have the data model file location, which is in the same folder, then at the end we have the generate section, where we declare we want to use the JavaScript based Prisma client to auto-generate our schema and then finally, the location of where this file is to be saved to. To work with this Prisma client, we need to install a Prisma client library, down in the terminal, we can do this from npm, so npm i and the name of the package is Prisma-clients-lib. It end sets pulls in from npm. The final piece of setup is to add Prisma onto our context. Just like we did with the sample data, this will allow us to make use of everything in this generated file inside of our resolvers in the index dot js file. For this to work at the top, we need to require the auto generated file, which we just looked at and store it in a variable called Prisma. So let's create a constant called Prisma and then we need to require the auto generated file, which we looked at before, this is in a file location which is dot dot slash Prisma forward slash generated and then forward slash Prisma client, which is the file name. We then need to add this Prisma variable on to the context, so down at the bottom below reviews, we can also include Prisma onto the context and that this will give us access to Prisma from our resolvers and this is what we'll be looking at in the upcoming videos.
19. Updating Our Datamodel: As we mentioned in the previous video, the data model file which you have open here, comes with a user type by default. We now need to obtain this data model to suit our projects. At the moment, the user movie and review types, will be the same as in our schema. When go out to schema.graphql, and then copy these three types, copy the review, the movie, and also the user, and then go over to our data model, and paste these in. You can also remove the user which has been provided by default. Let's say this. We then need to add the ID directives, each ID field, so @id and this is going to be to our ID field on the user. The same for the movie and also for the review. This ID directive is something which needs to add to a field on each type, when using PRISMA. Another useful directive is unique, which is useful for fields such as our email. Each email entry in the database will need to be unique. We can add this onto our user, your staffed email type, we can add @unique. Since we've changed our data model, we need now to do two things. First, we need to run a PRISMA deploy to update our PRISMA service, and we run this inside of the terminal. If we scroll up, we can see a list of all of the different types and fields which have now been created, amended, or removed, along with any relationships between them too. We also have a chance to get our database link again, and this is something you don't have open in the browser, adding rubbish from the link at the bottom. If we now go over this link in the browser, I'm going to reload. We can now see over, on the left, we have a user and movie and review type. The second thing we need to do is regenerating our PRISMA schema file. This was the auto-generated one we looked at before. Inside the terminal, run PRISMA generates, and then hit "Enter". This will now update our also generated file with the new types from the data model. We can see this if we open up the sidebar, and then go into generated, and then our PRISMA schema. Inside here if we scroll down, let's go a little bit further, we can see our type of movie. We can see lots of movie references as we go down, and if we do a search for mutation, you see how mutations are here. We have the create, update and delete movie. Same for review and also for the user type, which we've seen before. These files can get pretty complex, but PRISMA has its covered with pretty much any operation, we will need to perform on our database. We will begin doing this in the next video, where we start to change our resolvers to use a real database in place of the sample data.
20. Writing to the Database: Now we have generated our Prisma operations, we're now going to implement them in our resolvers. This will allow us to make use of our real database in place of the sample data arrays over in the resolvers.ts file. I'm going to begin with the mutations. Since we don't have anything in our database, you sketch a query. Let's start with this sign up mutation and we can begin by reconstructing our user to use Prisma. Let's set up our const of user and then this time we're going to use the context.prisma. Since we put prisma on the context, we can access it in this way. Then we call a prisma query on mutation by the method name. I'm going to use the create user mutation. So.create user. How do I know that is a create user mutation? Because prisma will take our types, such as user and make or create, update, and delete a version of each. Just like we've seen in the last video when we checked out the prisma schema. We have create, update and delete versions of our movie, review, and also user. In this generated prisma schema, one thing you'll notice is that prisma does not add the individual arguments. For example, create movie has a data property and then the state property points to a new input type and this way is just to keep things a little bit more organized. We can also search for movie, create input, add this in, and we can see the input type just here. This takes in an ID, a title, and any reviews. Back over to our resolvers, we can set up an object to construct our user. Inside of create user as in an object and then we can add the name, which is equal to args.name. Also use email, which is args.email. We don't need to add an ID. Since this is now auto-generated by Prisma, so we don't instill anything like we did above. In fact, we can actually remove this const.user since we don't need this anymore along with the push method tool because we're not pushing to the sample data any more. Definition of this mutation. I'm going to turn this into an async function by adding async in front of sign-up. This will allow us to use await just before we create our user. This is standard JavaScript and nothing specific to graphQL. This just means the code will pause or await until create user has finished. Then finally at the end we return the new user with this known place, we can test this will push to the database by restarting the server using npm start. We can kick this off and then go over to Chrome, open up the playground. We then go to our sign-up mutation, enter and we get our data back. Then the last thing to do is to go onto our database and reload. This looks promising we have our user and we have the value of one. We click on this. We then see the value which was entered in the graphical playground, now in our database. If we click on this user line over on the right-hand side, we see all fields like user. We have an ID which has been auto-generated, the name and email. Then at the bottom you have the reviews field and we will connect the user to the reviews very soon. Let's go ahead and create a new user inside the playground. So I'm going to this time as mini-mouse, change the email and then send this off, reload. Now we have two users inside of our database. Now we have our users all working. We want to do the same for create movie. If we scroll down, we have our create movie resolver just here, which I'm going to convert just like we did before with the users. So first of all, I'm going to remove the movie object, creates a new constant called movie and the sequence be equal to the context top Prisma. Then we're going to call a method called Create Movie. You can take in an object. We're going to pass in the title, which is going to be equal to the args.title, which will pass in from the playground. But I want to remove is push method. Want to keep the return statement in. The final thing to do is to mark this as async. We can then pause until the data comes back from create movie. Save this, and then over to the playground, refresh and go to the mutation which is create movie and send this off. I don't see any errors so that's good. Also add a new movie into here and also send this off too, reload the database tab. We see two movies in side of our database, which we just added. Great. We now only have one more mutation to update and this is create review. We will come back to this one in the next video and also look at connecting data, along with also how to check if a record exists in the database.
21. Checking if Data Exists & Creating Connections: The createReview mutation is going to be a little bit more in depth than the ones we've already created. This is because of its links to a user and a movie. Before creating this review will need to check both the user and the movie actually exist in the database. We also need to set up a connection to the user and also the movies, so we can get back the data we need. Let's start with createReview in the resolvers.js file. The resolvers' createReview, and we can start by making this an async function. Prisma clients allows us to check if a record exists inside our database by providing a property called $exist. We can use this to pass in an ID for the user and the movie, to check if they both exist before creating the review. Let's do this just above our review object. Const, we'll start with the user, we can access prisma off the context, then we can use the $exist method, to check if a user from the users table, I'm going to pass in an object, check if the user ID from our database matches the user ID from the args, so args.userId. Just after this we're also going to do the same for the movie. Just have to make constant called movie, then we can access prisma from the context. We can use $exists, but this time rather than the user, we want to check the movie table inside the database. We also want to check if the movie ID is the same as the one provided on the args, which is args.movieId. Good. Now have these two variables, we can throw errors if one or both of them don't exist. We can do this with a simple if statement to check if the user does not exist. The exclamation mark will do the opposite, so if user returns false, we will then run the code inside here. This code is going to be a simple throw new Error with a message of a string which is going to be, "user not found." Below this most want to add a second if statement, check if no movie exists. If movie is false, we can throw a new Error, and this one is going to say, "movie not found." Now if we go just below these two if statements, if we get to this stage, the user and the movie exist in the database. We can go ahead and construct our review. const, review, we are going to await this data mark from our database, so ctx.prisma, and then we can use the prisma method of createReview. CreateReview is going to take in an object and this review object is similar to what we've created just below when working with a sample data. Therefore, we can copy all the properties from this review object. I'm going to cut these out. We can also delete this constants and paste this inside of our review. We can also remove this push method since we're not push into our sample data anymore, and also the id property from our object since this is auto generated by Prisma. If we save this file and then head over to the GraphQL Playground. Let's reload this. Then we can go ahead and grab a valid movieId and use id from our database. To grab any user, we can copy the id over, add this in. Then we can do the same for our movie. Either of this is fine, add it into the movieId, then we can run our mutation. We get back an error. This is because we need to establish a connection between the movieId, provided with arguments, with a movie from the database, and also the same for the user. Prisma allows us to do this easily by using a connector. We can set this up in our resolvers inside of our review object. For now I'm just going to cut the args.movieId, set up the curly braces, and then we can pass in a connect object. Here we can pass in how we want to connect to our movies, and once you use the id field and then matches with the movieId from the args. We can also do this for the user, we can cut the args.userId, set up the curly braces, and our connect object. This time we also want to connect by the id. We connect this with the user id provided in the args, give this a save, and then if we rerun our review, reload the browser, and send this off. We'll get an error, cannot read property publish of undefined, and this is in createReview. Let's check this out. We have ctx.publish on the pubsub that looks okay. Let's just check this out in our index. It looks like when we seen the pubsub some reason off here. Let's just save this, reload and check this is okay. Now we don't get that publish error anymore. Instead we get a cannot return null for non-nullable field which is Review.movie. This error is expected. First of all, if we go over to our database and then reload, we see we now have our reviews we just added in, so the mutation is actually working. But the problem lies in the review data, which we're getting back. This is because if we go over to our schema.graphql file. Then if we go up to our mutation, here we can see we get back the type of Review, scrolling down to this Review type, which is just here. As we have already looked at, the scalar fields of ID, string, and integer will return a value from the resolver. Both our custom objects of Movie and also User will need a separate resolver to get the data which we need in the resolvers file. If we scroll down to our view type, we've already created these two review resolvers of movie and user. However, these are still searching for the sample data rather than the prisma method which we need. First of all, we can amend these by commenting or deleting out the code from before. Then in place we can begin to replace this with the prisma equivalent. We can return ctx.prisma, and what we want to do, that we want to search through the reviews. Currently we're accessing the reviews from our database. The next step is to find the current review by matching id with the one from the parents. We pass this in as an object, so much the id with the parent.id. Now have the review from our database. We want to return any movies associated with this review. This can be achieved by chaining on the end a movie method call. Right at the end, we can chain on the movie method to fetch all the movies associated with this review. We can do this with any data which is related. We effectively chain to cover the methods we have such as user, movie and review, and then filter the data on each stage as we go, such as he when the first filter down the reviews by the id, and then fetch any movie associated with this review. Below this Review type also has a relation to the user, so we can do the same with these two. We can remove the code from before. This time we're going to return a ctx.prisma.review. This is going to look very similar. We're going to search the review id that matches with the parent id. The only difference this time is we're going to search for a corresponding user by chaining on the end the user method, save this file and then back over to the Playground, reload the browser, and then send this off, and we can now see our review has been created. If you go to a database, this review is also appeared here, and we can click on this and checkout our view. Let's try one more. We can add in a different user. Copy the user Id paste this in, and then copy a valid movie. Copy this id too, add this inside of the args, and we can run this and now we get back the data we want. If we reload our database, we should see the review inside here. All of our mutations are now working with Prisma and pushing to our real database. Next up, we will move on to modifying our queries to also work with our new database.
22. Reading Data with Prisma Part 1: Now we already have a little experience of interacting with our database using Prisma. Updating our queries to fetch our data back shouldn't be too much of a problem since it's very similar. Our first query is for movies and I want to mark this as asynchronous so we can again await data back from Prisma. Then we can again access Prisma on the context and select the movies method. Let's comment out the code from before and in place we can create a new constant called movies. This too awaits our information back from ctx.prisma, and call the Prisma movies methods, pulling all the movies from our database then we can return our movies at the end. I'd have a return statements and we can return the movies and make sure this matches movies just above that. This is all we need to do for our basic query and we can test this out over in the playground. Let's refresh the browser and then to the tab which is for the movies. This is a query. We can rerun this and then we have our two movies but this time pulled in by Prisma from our database. If we want any relational data though, for example, the movie type also has reviews. If we look at this reviews property, we just have an empty array. For this we need to modify the resolver to also fetch the reviews. Back over in the resolvers file, scroll down to the bottom. We need to reduce this reviews resolver for the movie type to work with Prisma just like we did in the last video. Let's comment out the code from before and then in place we can return ctx.prisma. We're going to search through our movies so let's look for the movie method. Pressing in an object and we're going to search for the movie which you want by the ID. Well, let's match the movie ID with one provided from parents.id. Then just like we looked at in the last video we can also chain on the end our reviews method, pulling all reviews associated with this particular movie. Let's save this. Now, if we rerun our query, reload the browser, hit Enter and now we see for each movie we have a reviews array. This time it's not empty. It has all the reviews which is linked in our database. Next up we have the users resolver., so back up to the top of the file and then go to users. We could first mark this function as asynchronous, pulling commands our return statement from before. In place we can setup a constant called Users which is going to await ctx.prisma. This time want to search for the users and then we can return our users. Just like before, this works fine for simple queries which only returns scalar types. Well, our users also have reviews too so down near the bottom of the file, we need to modify the review resolver for the user type. Scroll down to our use type. We have a reviews resolver. Inside here we can comment or cut out these lines of code and then we can replace this with a Prisma method which will look similar to the ones we created before. We're going to return ctx.prisma. We're going to search for the users, pass in an object or we can filter the users by the ID. The ID we want check against is the one which lives on the parents. Then for each user, we can also pull in any corresponding reviews by chaining the reviews method on to the end. Off in the playground we can now test this out. If we look for the tab which is the user's query, hit reload and then send off this query. We'll then get back all of the users and the corresponding reviews for each one. Next we have the reviews query. This will follow the same pattern, so up at the top of the resolvers we can mark this as async, comment out the return statements and then we can get all of the reviews from Prisma, so const reviews. This is going to await our data ctx.prisma.reviews and then return our reviews below. Test this out in the playground, hit reload, up to our reviews query, send this off and our reviews and now return back from the database. Notice how this time our relational data which is the movie so with movie title here and ID and also the username at the bottom. This all seems to be working too. This is because we've already handled the resolvers to these cases earlier on. We did this over in the resolvers down in the review type. Scroll down to the review type. We have the user and movie resolver in place. We converted them to user Prisma earlier when working with mutations so they also now settled for our queries too.
23. Reading Data with Prisma Part 2: We're all done with updating the existing queries, they now work with Prisma. But before we wrap this up, I'm going to create one more query. This is to get reviews by a particular user. If you feel confident, you could go ahead and try this ourselves before follow along with me. Its structure will follow the same pattern as the other queries just here. I want to call my query reviews by user, which will take any user ID as its one argument. Then you need to create a matching resolver which first checks if the user exists and then returns all reviews for that one particular user. Okay, so let's begin in our schema by adding in our query. So that's schema.graftql. Up at the top with the type of query. We can add reviews by user. This is going to take in as its one and only argument, the user ID, which will return the type of ID. This is a required field, so we use the exclamation mark. A user may have multiple reviews, so it's going to return an array of the review type. After this is done, we can save this and then go to the resolvers for this query. Resolvers is.jsfile. Then after reviews we can add a comma. I'm also going to make this async. The name was reviews by user, which comes second, the parents, the args, the contacts and also the info. Setup our curly braces. The first step is to check if a user exists in our database. Let's create a constant called user exists. Then we're going to await the data back from ctx dot prisma. I'm going to use the $ symbol exists method to check if a user exists by a particular ID. We can pass in his ID into the object, checking if this ID is equal to the one provided by args, which was args dot user ID. Then we can check if the user exists in a conditional statement. So if the user does not exist, we're then going to throw new error. Passing in a error message as a string of user not found. On the line below, if we get to this stage, the user does exist. So go ahead and put in the reviews. So const reviews, we're going to await, ctx.prisma. The first I'm going to do is check the users and filter these down by the provided ID to search you all the users in the database matching the ID from the args. So user ID. Then we can chain on the end the reviews of that particular user. The final step is to return the reviews and then test this out over in the playground. Reload the playground, and then we need to create a new tab to create our new query. This query was called reviews by user, which you're going to take in the user ID. This user ID needs to be a valid ID from our database. So obviously the users, we can select any user, copy the ID, paste this in, inside the curly braces. We need to select which fields we want to get back. We're going to add the ID, the review text, the rating and then also the movie which this review is associated with. This is also an object. So we need to pass it in the curly braces, the fields we want to get back, Our response to add title. Run this query. So we've got 1, 2, 3 different reviews, which matches pretty reviews inside of our database. One final test, if we remove the digits from our user ID and then we run this, we get our message of user not found. Great hope you managed to give this a go by yourself. If not, don't worry too much. It's all a good learning experience and this is all now for our queries using Prisma.
24. Thank You & Next Steps: Congratulations, you have now reached the end of this course. If no, this is an introductory course. We have covered quite a bit of ground and hope you've learned a lot about GraphQL and Prisma. We began by looking at what GraphQL is and some of the basics such as setting up our server, setting up our types, queries, and mutations, and also how to create resolvers. After that, we looked at relationships between different types of the set resolvers to get our relational data before moving on to mutations and real-time data using subscriptions. Once we had all these covered, we moved onto setting up a real database and interacting with it using Prisma. We then converted our movie review projects to work with this database rather than the sample data which we started with. By now, you should have a good understanding of what GraphQL and Prisma are and what they can do for the back end of our projects. You can, of course leave it there, if you are just taking this course to sample GraphQL. Well, if you want to take things further, there are a few paths you can take. An obvious but really effective way of getting better at GraphQL is to simply build more projects. Take what you've so far and apply it to any project which you enjoy. It could be a personal hobby or interest, something work related, or anything else you can think of. Something else you can do is to make this project your own by making changes. You could personalize it by changing the topic, changing what data you get back, or even by adding new features. If you're feeling a little bit more confident, you could even add user authentication with a login and registration facility. You could add a feature to delete or update reviews or anything else which is good for you. Another option is to move away from the demo Prisma database and set up your own. There is a link here to the Prisma docs which has some guides on this. Another great step, will be to create a front-end to interact with our data. We have not covered the front end in this course since GraphQL is a back end related technology. But this is certainly something worth looking into. We've used the GraphQL playground to get our data but GraphQL is compatible with almost any popular front ends including, React, Vue JS, Angular, and iOS to name a few or here is a link to the Apollo GraphQL documentation. Apollo GraphQL has implementations for working with GraphQL on the server, making it an alternative to GraphQL-Yoga, which we've used in this course. Also, the Apollo Client can be used to build the client side of the front end of your application. If you go to the menu and hover over the client options up here, there are links to guides for lots of popular front end choices. Feel free to take a look over some of these. The final thing I want to show you is these GraphsQL Boilerplates. These are boilerplates based on Node, Typescript, React or Vue. Each one of these has three levels of boilerplate from a simple hello world example. Two advanced features using authentication and databases. These are really useful to use as a project starting point or even just as a reference. This is it now for the course. Hope you've really enjoyed it and hopefully I will see you in the course soon.
25. Follow me on Skillshare: A huge congratulations from me for reaching the end of this class. I hope you've really enjoyed it and gain some knowledge from it. If you've enjoyed this class, make sure you check out the rest of my classes here on skill share, and also follow me for any updates and also to be informed of any new classes as they become available. Thank you once again, good luck, and hopefully I'll see you again in a future class.