Headless CMS & GraphQL API with KeystoneJS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey what's going on guys so in this video we're going to be creating a back end to a blog using something called keystone js which is a headless content management system and it allows us to create a graphql api it gives us an admin area we can log into create our blog post we're going to implement users with authentication some access control and then you could essentially take this graphql api and you could connect to it from something like react with the apollo client which is really popular or really anything at all and if you're not familiar with keystone or graphql don't worry about it we're going to go through basically start from scratch and i'm going to explain everything as we go graphql is is essentially a query language that um you know you can connect to with just one endpoint as opposed to a rest api where you have all these different endpoints all these different routes that you would hit to do certain things and in fetch data and with a rest api you really have no control about the data you get from that endpoint uh let's say you wanted just uh just the title from 100 different blog posts you can do that with graphql you can't do that with a traditional rest api so we're going to go ahead and jump in this is keystonejs.com and the documentation is is pretty straightforward so if you have any issues uh you don't understand something that i talk about you can find it in the documentation so if we go to getting started here we will need a database to get set up and you can see that keystone supports both mongodb and postgres i believe you can also use it with prisma but we're going to use mongodb and you can install it locally if you want but we're going to use something called the mongodb atlas which is a cloud database it's basically mongodb in the cloud so i'm going to go to mongodb.com and you just want to if you're following along just register it's completely free no credit card needed or anything like that and i'm just gonna sign in here uh let's have a couple different accounts i think this is the one that i want okay so let's see so if you just signed up you won't see this right here basically what you want to do is create a cluster so you'll see a green button create a cluster just choose the defaults aws is your provider and it'll just set you up with a free tier and you'll be able to have a cluster where you can then create databases with collections so once you have that created just click on collections and this will show all the databases as well as the collections and the data if you do have any data so from here we're going to say add my own data and database name i'm just going to call keystone blog and collection let's just create our post collection all right so now we have a database keystone blog with a post collection now there's a couple other things we need to do before we move on to keystone one is the user so if you go to database access and say add new user you just want to create a new user here i'll just say brad123 user and password leave the defaults and then under network access you're going to want to add an ip address now you can allow access from anywhere this is basically to connect directly to the database so if you say allow access from anywhere you can do that you can also add your actual ip address which which i'm going to do because i did run into some connection issues when i don't do that i think it's because of my vpn so i'm just going to take this off screen for a second and add my ip address and confirm and now i can bring this back over all right so we should be all set up now the next thing that we need to do is go to this connect button and then connect to your application and this is the string we're going to need to put into our code when we're ready to connect but you do have to replace the angle brackets password and this angle brackets db name with your database name so i'm going to copy that i'm just going to paste this off screen real quick and just replace replace my database name with what i call a keystone blog and then place my password and make sure you also replace the angle brackets all right so then i'm just going to copy that and now we're ready to move on so i'm going to open up my terminal here and the way we can get this few ways we can get started we're going to use create keystone app which will just generate kind of a boilerplate for us and i'm going to use npx so you do need node.js installed i believe you need at least node 10 to run keystone so let's say create create dash keystone dash app and then whatever we want to call the folder i'm just going to call it keystone dash blog okay so now it's asking us for a project name you can call this whatever you want i'm just going to call it keystone blog and then it's going to ask us which database we're using we're using mongodb and now we need to put in where our database is located if it's on your local host it'll look something like this but i'm going to go ahead and just paste in that string that i copied from atlas i'm going to say yes to testing the connection that was successful and then i have a couple options here so this this first one you can actually have the users and authentication all set up for you however i don't want to do that because i don't want to just throw a bunch of boilerplate code at you guys and you won't know what's going on so we're going to go ahead and choose blank and set that stuff up ourselves okay so we're all set let's cd into keystone blog and then i'm just going to open up vs code in that directory okay so now we have all our files on the side now we chose the blank template so there's not really much here in the package.json you can see we have some keystone modules including the mongoose adapter so it uses mongoose under the hood to interact with mongodb the app admin ui is the admin gui tool and then we have graphql we also have graphical which is a client to make queries and mutations to the to the api which which i'll show you and then keystone and then we have this dev script to run our dev server now it runs on on port 3000 by default but i'm going to change this so i'm just going to add port equals 5000 here just because if you use something like create react app and you know you have your front end dev server on 3000 we're going to run this one on 5000. so that's the only thing i'm going to change there and then in the index file there's not much here again we chose the blank template so we're just bringing everything in bringing in the adapter we have our project name we have the adapter config with our database string which i don't want to keep in this file i'm going to put that into a dot env file in a minute but then these comments will get rid of then we have just initializing keystone with the adapter and finally we're exporting keystone we have this apps array with the graphql and the admin ui app so that's pretty much it that's all they give us to start with but we should be able to start the server so i'm going to go ahead and just open up my terminal here and say npm actually i'm going to run npm install even though the dependencies got installed sometimes i run into some issues if i don't do this okay so now we can run npm run dev and that should start on port 5000 and you might see this missed message here no cookie secret value was provided we'll we'll fix that in a minute but what we have here are our three urls so first one is is to the admin interface the second one is to graphical which is the client we can use to directly make queries and mutations and then we have the actual api url so we're going to go to the admin area here and there's not going to be much because we didn't choose to use authentication and have that stuff included by default we're going to do that on our own so basically it just says no lists is def no list defined a list in keystone is is basically a schema or a model if you've ever used mongoose or sqlize or something like that you know you create your your models with your different fields and stuff so we're going to have a post list we're also going to have a user list we don't have anything now so it just doesn't show anything and then this link here graphql playground this takes us to the graphical client where we can make queries and and i'll get to that right now we have nothing to query so we're going to close that up and go back to vs code and we're going to cut this off so we do have to restart the server when we want to you know make changes um one thing i'm going to do is install env so we're going to install that just so we can have some environment variables i don't want to have my database string right here in the code so while that's installing i'm just going to go ahead and cut that and we'll be able to say process dot env dot and then underscore uri now to use these environment variables in a file we have to include dot env so let's say const const.env and set that to require dot env and just add on to the end of this dot config and parentheses okay now in in our file structure here we're going to create a file called dot env so period env and let's create a uri and let's go ahead and paste that database connection in and we might as well add the cookie secret here as well just to get rid of that message otherwise it's just i think it randomly generates it every time you start the server um so cookie secret this can be anything just say abc123 and there's a vs code extension that i have installed called dot env that's why you're seeing the color highlighting here you might not see this but you can install that extension if you'd like all right and i just want to make sure that actually we have to add our cookie let's see so right here let's say cookie secrets and set that to process say process dot env dot cookie underscore secret and then let's just run it again just to make sure that everything's okay and while it's loading in the front end here you'll see it'll say like keystone loading all right now there's still no lists or anything so we're going to go ahead and do that now cut that off and for the list we're going to put them in their own files so let's create a folder called lists and inside lists will create a file called post dot js okay capital p singular and we want to bring in from here the field types so let's say require and we want to set this to at keystone js fields and the fields that i'm going to want to bring in here are text select and relationship which i'm not going to use just yet we're going to wait until we have users that we can so we can assign a relationship to a post from a user and then let's create a variable here we'll call this post fields and set that to an object that has a fields object inside that and before i forget let's just export this so module dot exports set that to post fields and the first field that i want for our blog post is a title um so the title is going to have a type and the type is going to be text okay and then i'm also going to give this an is required and set that to true okay and then let's see we have a title let's also do a body so body was going to have a type of text as well however i do want this to be a a text area in the admin ui so we can add this is multi-line and that should make it a text area so we want to set that to true um let's see what else do we want so we have title body let's do a status status we're going to give a type of select and when you have a select field you can add your options which is going to be an array with an object and we're going to have a value here for the value let's say published for the first one and it's going to be all caps for the value but then we can have a label and just say published all right and then we're going to copy that down let's do unpublished so unpublished and then this will be unpublished and then we can also have a default value so let's say default value and the default will set that to published all right okay so title body status and then we want an author so let's say author and for now i'm going to set the type to text but later on it's going to be a relationship and then let's also say is required and set that to true okay so that should be it now to to use this list we have to of course bring it into our index.js we're going to bring this in up here let's say const and we're going to call it post schema and set that to the file which we want to require dot slash list slash post and then we want to go make sure you go under here because we're using this keystone object and then on that we have create list and we want to give it a name so this is the post list and then we want to give it its schema so it's similar to what you would do just using mongoose directly all right so we'll save that and then let's go ahead and run and we're still not going to see you know authentication or anything yet because we haven't added that but now you can see we do have this post area so we have a table obviously we don't have any yet but we can go ahead and create so let's say post one this is post one and it's published by default and for now i'm just going to type in the author and then this is like a summary of of our data and then we'll save changes we get a little you know saved successfully up here so we have one post let's create another one we'll say post 2 this is post 2 author we'll say john for this one okay save changes and that was added good so we have our posts and we can of course you know update them and if you go to your mongodb atlas and you go to collections you should see your data you could also use mongodb compass which is a desktop tool yeah so these this should load we should see our posts i don't know why this takes so long if you're yeah if you're gonna want to you know deal with your database directly i would i would definitely recommend using compass not this but you can see post one post two good so now let's go ahead and before we implement users and authentication i want to check out this graphql playground this graphical tool so we're going to make this a little bigger and from here we can write queries so let's go ahead and do that let's actually we just want to say query and in here as soon as if i start to type the word all you'll see i get a drop down with this all posts so any list that we create like if we create a to-do list all to do's will automatically be accessible to us through here so we want to say all posts and in here is what we want to return so we want to get let's say the id and the title and that's something you can't really do with the traditional rest api you just get all the data but here we can query specific data and you can see it just gives us you know the id and the title of all the posts we also have this underscore all post meta i don't want that and in here we can get like the count so if we run that you'll see i'll get the count which is two we have two posts and then if you want to mutate the data so if you want to create a new post update delete that's that's where you would run a mutation so let's say mutation and just like with all posts we also get create post and create posts if we want to do multiple so let's say create post and then in parentheses we want to pass in a data object here and we can add our data so let's say title we'll call this post three we already have two what else body let's say this is post 3 and then we have author say brad and then status is published by default so i'm just going to have these three fields but then here we can also say what do we want to return back from this new post let's just get the id back all right so i'll press play or run and there we go so we get that id and then in history this history button we'll see all of our past queries and mutations and let's say we want to fetch all posts again we'll say use and then run and you can see that post 3 is included and if we go back to our admin area here you can see oh you have to reload you see post three has been added all right so this is a really nice tool to just you know get familiar with how to make queries and mutations so now we want to do is implement users so let's cut the server off and i'm going to go under lists and create a new file called user.js and we're going to pretty much do the same thing that we did for our posts we want to bring in let's bring in at keystone js fields and what we want to bring in as far as fields let's get text so we have email um password is is a field we want to bring in and then also let's bring in check box because i'm going to have a box for is admin all right so we're going to have an admin role for users so here let's create user fields and we want an object called fields and then down here let's module dot exports user fields and the first field for a user is going to be the name and that is going to be the type of text and let's say is required and we'll say true for that and then let's do an email actually i'll just let's just copy this down so we're going to have i think four fields so the next one is going to be email which is going to be text required and let's also make it unique so we can actually add is unique true next one let's see this one's going to be password and the type field type is going to be password and then let's see is required is true and then let's have um sorry about that let's have uh is admin and that's going to be a check box all right so that should do it let me just shut this ringer off all right now we need to bring this in just like we did with the post so right here let's just copy this down and bring this in from user this is going to be user schema and then down here this is going to be we're going to create a new list for user and say user schema now before i run the server i just want to add a relationship between the author the post author and users so we already brought in the relationship type so all we have to do is go down to author and instead of text let's say relationship and then we just want a reference to another list which is going to be the user list or uppercase user list and then let's set many to false because it's only going to be you know one post is going to have one author so i think that should do it let's save and then let's run our server let's reload this we're still not we still don't have authentication we haven't done that yet but you can see we do have a users area and we can click create and let's create a user here and email will say admin at example.com set password i think it has to be eight characters minimum so i'm just gonna do one through eight and i'm gonna make this user an admin save changes and then let's go back and let's create another user that is not an admin so we'll say john doe we'll call this let's say user at example.com password okay and i'm not going to check is admin for this user all right so we have our users now to do authentication let's go back here and let's see i'm going to just close these list files up we don't need those and we need to install uh we need to install something called uh password auth i believe let me just double check um off password so let's say npm install and it's going to be at keystone js slash off dash password and then we want to bring that in up here so we'll go right here and say const and we want to bring this in from keystone keystone js slash auth password and what we want to bring in from it is our password strategy so it's going to be password auth strategy and then down here let's create a strategy so make sure you go under the list and let's say const auth strategy and we're going to set this to keystone dot create auth strategy which takes in an object and we want to put the type which is going to be our password auth strategy then we want the i think it's the list let me just double check let's see where is it uh yeah so we want to put our list that is that we're using for this which is our user i mean it could be like staff or something like that i would imagine in most cases it's user and then type not type config so config we want to just tell it which fields we're using for like the username and the in the password so the first one is going to be identity field and for us that's going to be the email of course you could have username if you wanted and then for the secret field we're using password okay and then i believe that's it so we just need to add that down here where we have our admin ui app these values here we're just going to tack on auth strategy save that and now when we run our server when i go back to the browser here and reload we should then see a login page okay so here's our login page and and you can actually create a react hook to replace this logo if you want and to change this up a little but right now any user can log into this area so i'll say user at example.com it doesn't matter right now if there is admin or not you'll see i'm able to log in i can you know create posts or whatever and it says logged in as john doe one thing that we can do now though if i click on to edit a post or to create a post there's this uh and i didn't even show you this yet that we could drop down like that but you can also click this button here which will just put in whatever user you're logged in as which is nice so for this one we'll choose brad for this one brad all right so let's make it so that only admins can log in um if you have a site where it's just like your personal blog and you don't you don't need front end registrations or anything like that then this is fine but you might want to have different roles so i'm going to show you how to do that so we'll go ahead and sign out okay and then let's go back cut the server and in this add this new admin ui app in the export we can add is access allowed and that's going to be a function so we'll pass in an arrow function and this takes in an object and we're going to destructure it and pull out authentication and then destructure that and we're going to pull out item from that which is the user so we can actually just rename it to user and then whoops and then down in here in the function body let's console.log the user just so you can see what that gives us and we need to return from this a boolean so it has to be true or false now we have this if it's a successful login user will be full right it'll have the user object so let's say return and we don't want to it's hard to talk and type we don't want to return the user object itself we want to return true if it's there so i'm going to put the double bang in front of it so we're basically saying if this user is here then return this as true but we also want to check to see for admin so we're going to say and make sure that user dot is admin all right so we'll save that and now let's run our server and let's reload and now if i try to log in as user it shouldn't work so let's say user at example.com okay so it didn't let me log in now let's try admin at example.com and i can log in so now it now the user has to have that is admin field uh in order to log in okay now that only pertains to to this admin area it doesn't comply it doesn't complain it doesn't pertain to uh to our api itself so if you were to use like react and apollo or anything use curl whatever to to hit this api you'd be able to add posts add users delete them and all that so we can set up some access control and it basically we're going to use this same function and just to show you what that logged for us you can see it logged the user right here all right now i'm going to actually take this function so from here to here let's cut that and i'm going to put it in a function called is admin and then const is admin set that to that function all right we don't need to uh console log the user and get rid of that and then i'm also going to just have another one here but this one is just going to be is logged in we'll just remove this right here so it'll just check for the user it doesn't matter if they're admin or not so we have these two functions we can use now in the schema we can actually create some access control i'm sorry not there right here in the list so we have post and then post schema but we can take this away and put in an object and then just put in fields and then our pose schema dot fields object so this this is basically doing the same thing as we just had however we can now add more on to this like axis and we could set this to true or false um and it would pertain to you know reading create delete all that or we can set it to an object and set read for instance we'll set that to true since that's public excuse me but let's set create uh let's set that to is logged in and we'll do the same for update and delete so let's say update and this one here let's say delete and then for the user what i'll do is just copy this and let's replace this and see we'll change this to user change this to the user schema and instead of logged in let's just i'll just select all this change that is admin so this way to create a user or update or delete a user you have to be an admin now just to test this out temporarily i'm going to change the access to the admin area to just logged in just so we can test this out and i can show you that the user or john doe who's not an admin won't be able to to do any of this stuff so let's restart the server and let's go back and reload excuse me all right so now we should be able to log in with user at example.com and if i go to users and i try to create a new user it'll show me like the form and stuff i'll just put whatever in here set password so create and notice i get this access denied error you do not have access to this resource so our api is protected even though i'm able to to come into this admin area the api is is protected if i were to try to let's say delete a user you'll see i can't delete the user okay so that that protects the entire api not just the admin area so let's um let's go back here and just change change that back to is admin i just wanted to show you that all right so that's what i really wanted to show you is how to create the api how to create the admin area authentication and all that if you want to use this on the front end which i do plan on doing a video on you could use the apollo client so just to kind of give you an example you could use this with react or view or whatever um so basically you would install the client install graphql and then connect to it so create this new apollo client and the uri you would put in here is the admin slash api okay that's your api url and then you could create a query like this so client.query gql and then this here is basically the same thing that that we did here so if you want to get all posts you would put that in here and you could you could call you could name it and then get that data and then to use it there's a hook called use query and if it's a mutation there's a hook called use mutation all right and i will do a video on that uh within probably the next few weeks or so hopefully but that's it guys i hope that you enjoyed this i hope you learned something from it and that's it i'll see you next time
Info
Channel: Traversy Media
Views: 45,332
Rating: 4.9694476 out of 5
Keywords:
Id: 3cH1BXJbfa4
Channel Id: undefined
Length: 32min 53sec (1973 seconds)
Published: Mon Feb 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.