Fullstack Type-Safety with GraphQL and Hasura

Rate this content

In this workshop, we’ll learn how to build a type-safe chain from API to the client with generated TypeScript tooling. Creating a type-safe environment for development reduces the number of bugs that get shipped to production, but also creates faster feature development once the ground-work is in place.

This will be a fast-paced workshop covering an opinionated stack of features, but in the end, you’ll have a functioning framework for eloquent and type-safe development.

Table of contents

- We’ll begin creating a GraphQL API on Hasura Cloud and define some basic access controls and actions.
- Then we’ll scaffold a TypeScript-ready framework with NextJs.
- With the framework and API in place, we’ll generate an SDK using GraphQL Zeus.
- Lastly, we’ll generate some type-safe state management wrappers with easy-peasy for implementing a basic login and authentication flow.

203 min
19 Oct, 2021


Sign in or register to post your comment.

Video Summary and Transcription

This workshop explores back to front type safety in building front-end applications using TypeScript and Next.js. It covers setting up a cloud project with Hazura, creating login and signup actions, handling API endpoints with a Next.js application, and querying and displaying user data using Apollo Client. The workshop also includes setting up state management with easy peasy and debugging authentication and state management issues. Overall, it provides insights into building future-proof, stable, and secure apps using these tools and technologies.

Available in Español

1. Introduction to Back to Front Type Safety

Short description:

In this workshop, we will be exploring back to front type safety. We will generate a GraphQL layer for type safety in building front end applications using TypeScript and Next.js. TypeScript helps reduce bugs in production code. Let's learn how to build more future-proof, stable, and secure apps using these tools and technologies.

My name is Jesse. I am going to be leading, working with you today in this workshop. And I am a developer outreach person for Hazura. Hazura is a cloud provider and beta layer provider doing all kinds of amazing things. If you are not familiar with us, definitely check it out. We'll be having a look at some of what it does today. And this is the back to front type safety workshop.

What does that mean? That means that we are starting with a concept of generating a GraphQL layer that is going to be our type starting point. And we'll be using that to generate an SDK to essentially give us type safety for building front end applications using a TypeScript application for Next.js.

Now, here's some critical pieces to know about that process. One is, I'm not a TypeScript guru. So, I'm like the sweet spot of what TypeScript is actually supposed to be solving. And maybe many of you are as well. TypeScript is actually helping us produce less bugs in our code that we ship to production. So, there will be some cases where maybe even many of you know the answer better if a TypeScript error arises. And in that case, I would love to have you let me know. I'm not proud. I'm not going to pretend like I'm the TypeScript person. I am a GraphQL person. I am a data modeling person. So, questions around that, I'm definitely happy to help with. But this is basically all of us learning how do we build apps in a more future proof, more stable, more secure way going forward with some tools and technologies that really have provided a lot of stability and yeah, type safe footprint for the community as a whole. So, that's basically the premise.

2. Introduction and Workshop Guidelines

Short description:

We're going to start from scratch and build this together. Feel free to turn on your cameras, ask questions, and code along. Let's make this a collaborative experience.

What I have, if you'll see the GitHub repo, we're going to start from scratch. And as we go through, I will be pasting code both inside of the, you'll be seeing the code inside of the window. We'll build this together. And then I'll be making most of that code available through the repo. And what I'm wondering, because at the moment, nobody else is turning on their cameras. So, it may just be, you know, a bit of watching me code today from what it's looking like. Hey, I've got somebody.

What we may do is I may just start to flesh out this repo as we go through and then we'll be able to kind of keep pushing it forward. So, I really appreciate having the first camera on. This is a casual workshop. This is not a here's my slides and please don't ask me any questions. Everybody is allowed to turn on the cameras. You're allowed to interject, raise your hands, have a question. We've got breakout rooms available. If there's a spot where we say, hey, let's go ahead and take five minutes and let, we'll break it up into smaller groups to kind of figure out what we're doing. But it's meant today that everybody can kind of code together. So, does that sound good? Are there any questions before I get started? I'm looking at Zoom. I'm looking at Discord.

3. Setting up a Cloud Project with Hazura

Short description:

To get started, set up a cloud project with Hazura by navigating to cloud.hazura.io/projects. Sign up for an account, and if you don't have one already, set up a Heroku account for faster database connection. Take a look at the pricing page to see the free tier, which offers a gigabyte data pass through and 60 requests per minute. Next, set up cloud accessible API resolvers using ng-rock or other services like Versal or Heroku. The workshop provides a Git repo with a breakdown between a backend folder for continuous integration with Hazura and a Next.js application for the front-end. Set up environment variables, including an action-based URL, a Hazura GraphQL unauthorized role, and a JWT secret. Ensure you have a way to add a database, preferably a Heroku account, and have your Hazura project set up. Let's proceed by hitting the free tier and giving the project a name. After setting up the dashboard, test ng-rock to see if it can open a port before having an active port listening. Copy the forwarded address and keep the session alive. Set up environment variables by initializing them with the appropriate values from the readme file in the Git repo.

All right. So, we're going to get started. To begin with, what we're going to need to do is get a cloud project set up with Hazura. So, to do that, you can go ahead and navigate to cloud.hazura.io slash projects. Now, I am already authenticated. So, that's where we're at. So, I'm going to give you all about two to three minutes here to go ahead and get yourselves an account signed up before I just keep moving. And I'm just going to push the new project button here and I'm going to leave it sitting on that screen while we wait. And we're just setting up our SaaS provisions for right now. So, again, if you don't have one already, I highly recommend setting up a Heroku account as well because that's going to be the fastest way to connect a Postgres database to Hazura because we have that as a top level integration. But, yeah, feel free to bring your own database.

While you're all doing that, let's go ahead and just have a quick peek at the pricing page. So, when you see the free tier here, which we'll be using today, I always find a bit of comfortability to know what this free actually mean here. Is it a this turns off in 30 days? No, it is free forever. You got a gigabyte data pass through and 60 requests per minute. That is quite okay for developer free tiers. So, this definitely will let you do a hobby level project in production, especially because we have built in caching and stuff. So, feel free to use this and not be worried that it's going to turn off on you for any of your personal projects. So, while that's going, and if you weren't catching the name of the database provider, that's going to be Heroku. So, again, I'm already authenticated, but you can easily create an account, follow that up, and you can use that to create a free account. And all you need to do is have an account. The rest of it will be automated for us. It's just having the account existing that will be helpful in this case. So, give this another two to three minutes because this is kind of the slow part.

The third thing that will be helpful at some point will be we're going to need to have cloud accessible API resolvers, which I've mentioned a couple of times at this point. I will be using ng-rock, which is this service here. And what it does is it creates cloud tunnels directly to your computer. This has been around for a long time, so it's not like some ultra hacky solution. But they have a very basic free service here. This is going to be the one that I will be using today. You can use Versal. You can use another Heroku application to deploy your next app. I ended up going with this because the repo that we're basing this off of today, and I'll give you a bit of a code walkthrough on this, and then I think everybody should be caught up on their stuff. So, what we have here at the very top level is a breakdown between a backend folder here, which has the metadata structures you would need to set up a continuous integration with Hazura. That's a beta service right now, and as of this morning, it was not giving me confidence that it was going to be a good idea to throw 30 of us at it all at once. So, I'm going to be walking us through utilizing the other ways to set up a Hazura project, which is not a problem at all. So, if you wanted to take this repo, and I will be getting this even more and more fleshed out in the next day to just put all the stuff that we're going through today. This is the first time I'm teaching this workshop, so there's a lot of discovery as well. So, I'm taking that learning, and I'll be making this repo clean. We'll be dropping all the code in there. So, you could use this to have the backend be set up for a continuous deployment strategy, and then the front-end application is just simply where I was storing the web application that was connected. This is a Next.js application. Again, we're going to be doing this step together, so don't worry. We're going to do this together, so it's all okay. All right, so hopefully at this point, you have a way to be able to soon add a database, ideally a Heroku account, and then you have your Hazura project set up. Ideally, you're seeing a similar screen as what I have set up. If there's anybody who's stuck, do let me know in the questions, and we can go over that, but I'm not seeing anybody panicking in the chat, so we're going to go forward. All right, so let's go ahead and hit free tier here. Actually, before we do that, let's give it a project name, because project names are everything right. So I'm going to go ahead and call this one the RA Workshop Live. That's for React Advanced, for those of you that are still waking up this morning. Error creating project, tenant name not available. Somebody else took my project name. All right, so I'm going to remove the hyphens on mine, and we'll go RA Workshop Live without... That's just so ugly looking. I'm going to call this RA-Jesse Workshop. Let's see if that gives us anything. All right, so now what we've got here is our basic dashboard that we're going to be using to set up a lot of the pieces here going forward. So at this point, I'm going to do a quick test here that I didn't do ahead of time. So I'm going to open up Terminal here, because using ng-rock is going... And if I'm saying this name wrong, as somebody knows, feel free to correct me, because it's just going to make all of us mad by the time that we're done today if I'm saying this wrong over and over. So I'm going to test this to see if ng-rock will let me open up a port before I even have an active port listening on this side. So we're going to test this out here real quick. And the command for that... Let's go ahead and boost this font size. You can see my errors here. That's nice and fun for y'all. We're going to go ahead and do this ng-rock HTTP 3000, because what it's wanting to do is it's wanting to forward a public port or a public server address to the port 3000 on my machine here locally. And my question is, will it work if I don't have anything listening? It appears like it is. So this is what we're going to do. We're going to go ahead and copy this forwarded address. The HTTP here is totally fine. And we're going to need to keep this session alive. Otherwise, you'll have to change some settings here in a little bit. And I'll tell you why that is. Because over to our dashboard now, we're going to immediately set up some environment variables that are going to be helpful for us throughout the remainder of our project. Now, if you are following along with the Git repo... And let me go ahead and put that into the screen here. You go to the readme at the very beginning here. So what we need to do is we're going to init some of our environment variables. Looks like my formatting is a little bit wonky there. I apologize. We're going to need to add an action-based URL. That's the one that we just copied here. We have a Hazura GraphQL unauthorized role. That is going to be something that gives us the open permission access to our GraphQL endpoint. Otherwise, it's fully locked down. And then we're going to need to add a JWT secret, which I'm guessing everybody's going to probably have the same secret today. Bad practice. But no.

4. Setting up Action-based URL and Anonymous Role

Short description:

We'll start by setting up the action-based URL and the anonymous role as environment variables.

We'll live. So we're going to go ahead and start with our action-based URL. So heading back over to the workshop project here, I'm going to go ahead and say new environment variable. And the name that we wanted to give that is going to be the action-based URL. So we're just going to go ahead and call it this. And that's the key. Try that again. Action-based URL. Good. And now I'm going to paste in the value. That's the GitHub repo. Good. That's my base. So yours should be something different if you use mine. You'll be disappointed. All right. So we have the action-based URL added. The next environment variable we want to add is going to be that anonymous role.

5. Setting up Permissions and Environment Variables

Short description:

Hazura has a very eloquent set of permissions and how we can set up our data layer and access. We're identifying a special role that is the role that I can use throughout the rest of my permissions checks. We define the Hazura GraphQL unauthorized role as 'anonymous' and add the Hazura GraphQL JWT secret. The JWT checker allows us to set the encryption type and define a specific name for a cookie inside the header. We configure the rest of our environment variables manually. We launch the console and explore the different parts of the Hazura platform, including the API Explorer, graphical explorer, actions, remote schemas, events, and monitoring. Finally, we move to the data tab.

So Hazura has a very eloquent set of permissions and how we can set up our data layer and access. What we're doing in this case is we're identifying a special role that is the this is the role that I can say throughout the rest of my permissions checks. And this stuff's going to make sense in a minute. But this is the role name that I'm going to be able to use throughout everything else and say, like, permissions to select things, to update things, which you shouldn't give any update roles to anonymous user. But we're going to go ahead and define that here now.

So if I just look for just typing in roughly like unauthorized, I'll see the default, the environment variable here. That's the Hazura GraphQL unauthorized role. And I'm going to give mine the name anonymous. That's sort of a best practice with a lot of the demos and things that we do at Hazura. So if you want to be stealing code, you may be happier choosing that name versus another one. But it's okay if you want to have a different name. And with that one defined, we're going to go ahead and add in the last one here, which is going to be the Hazura GraphQL JWT secret.

Let's go ahead and have a look at what's happening here. So here is here's what's going on. So this is the JWT checker. The key, again, this is a key you shouldn't use. I will, but you shouldn't. You should use a secure key here that is only known by you and the server. And then we're setting the encryption type to actually check it with. And then here's the critical part that's actually a little bit new if you're already familiar with some Hazura stuff. We can give a specific name to a cookie inside the header to actually allow it to check for servers or HTTPS cookies. So previously we were always sending that from the client. You can send JWTs from the client. That's okay. There's a lot of conversation about whether or not storing JWTs and things like local storage or unprotected cookies is technically not great because, you know, anything can access it even though it is an encrypted token. With the HTTPS cookies, which we have support for now, you can actually go ahead and define whatever cookie you want to call this and pass that on. And in that case, then we're able to reset that cookie in our application today. That's going to give us a very protected way to authenticate ourselves against our server. So good stuff.

We're going to go ahead and copy this whole thing. And we're looking for the Hazura GraphQL JWT secret. So I'm going to kind of move this thing out of the way, I wonder. I don't think you see it maybe, but I see it and it bothers me. I think I can move it over here probably. Yeah, that works. Okay. You should still be seeing my screen just fine. Going to go ahead and go back to the console. We're going to delete that page because we don't need it. And I'm going to go ahead and go to here now, adding in the next environment variable. So we're just going to do a search for JWT here. Again, we get a prompting for the one that we need. And we're going to go ahead and paste in just that value as is. I'm going to go ahead and add that. If you didn't choose a long enough key, it'll yell at you. So you'll have to definitely make sure that it's a 32-bit character. And from there, we look at our steps for what we needed here. Our environment variables are created. So here we have the next step. If using CID, which we are not, we will skip over that. If you are using, and I can show you where it's going to be at. So it's pretty straightforward. You would go to git deploy. You would identify the repository you have forked from this one, and then you would be able to connect it to that repo and then give it the path to the backend or whatever you want to name the folder. And it will find the config.yaml file, which then points to the metadata files that you need. So that's not what we need for this case. So we're going to skip that. What we're going to do is we're going to go ahead and configure the rest of ours manually here. So again, I'd recommend using the GitHub repo to follow along here, because you're going to want to do some copy and paste here. What we have is an SQL statement that we're going to be able to use for, in just a minute, for our tables to get sort of a user model that's defined the way that we want it to be defined. So let's go ahead and go back to our project. At this point, we can go ahead and launch our console. Give that a second to boot up. And here we have a running system. You probably have seen on the free tier, you only had access to the US market. If you were using the paid tier, you could obviously put this cloud install wherever you would like. So from here, if you're not familiar with the Hazara platform, we can do a quick walkthrough, kind of see the parts. We have here is the API Explorer. This allows you to do things like checking on your security parameters for global access. We have things like setting up REST endpoints for resolvers. I'm going to skip over these very quickly, because we're going to go over this maybe a bit later if we have time. We have the graphical explorer. So if you're new to GraphQL, this will be your best friend, because this allows us to actually explore GraphQL locally. We will be doing that as we go along. So I'm not going to spend a lot of time on it. I'm skipping data for now, because that's where we're going to end up. Actions is where we're going to be defining custom mutations for our service, which we'll also be doing here very shortly. Remote schemas is where you'll be adding in any sort of remote data source. If you had another GraphQL API you wanted to merge in. Out of the scope for this one, lots of resources for this workshop, but we have a lot of resources for that if it's something you're interested in. Events is triggering database events that you'd be able to listen to. So you can do some nice functional reactive programming patterns here, where you could say when a user is updated, alert the media, whatever you want to do. And so it's a good system, but we're going to not worry about it today. Monitoring, we'll only very briefly look at this for now. This allows us to see some overall health checks, operations, and behaviors of our service. Not something we're going to be doing right now. Probably not even doing it all today. We'll see what time allows for. But this is probably the single biggest value of cloud is built-in caching, built-in observability that allows you to be able to see GraphQL metrics that are sometimes tricky to plumb yourself. So to the data tab, which is the next step we need.

6. Setting up Database and GraphQL API

Short description:

To set up the database, you can either connect your own database or create one using the Heroku tab. Hazura allows you to manually track tables or track them all to get an immediate GraphQL API. We'll be building a basic user authentication system with login and signup actions. The authenticated token will be stored in a protected cookie for client requests. If time allows, we'll use the easy peasy library for state management.

All right. And so what we're going to do here is if you have your own, if you have your own, not GraphQL database, if you have your own database, you can connect it here with the parameters that you need. If you are wanting to just do this the fast way, we're going to come here to the Heroku tab and just hit create database. And that's going to probably for most of you request that you authenticate against your Heroku account. And once you've authenticated, it'll then allow you to create a database, which with a push of the button like I'm doing here, using the hobby tier of the Heroku database. So there are some limitations of the hobby tier from Heroku, most of which for hobby level things, you'll never notice. But worth mentioning, I don't believe you can change tiers with Heroku, if I recall right. So it's not like if you knew that you wanted to eventually have a higher level database with more advanced features, I don't believe you can actually just click upgrade it. I think you have to start with the right one from the beginning. I think, do not quote me on that. Heroku, do not get angry at me. So we have our database set up. So from here, we have a couple of options, how we could go about creating our data model. Now, again, I'm like the cloud person. So I like doing this stuff in the cloud. A lot of other people may like doing this either ways. But so one way to go about it is you come inside of the actual public schema here, your database. I'm going to go ahead and hide these little pop-ups here. I'm going to go ahead and say, create a table. And then I can come in here and name things. And I can provide custom columns and other things that I'd want to do. Typical database modeling kind of things, a la GUI. Now, in this case, I'm going to have us go ahead and save up some time on this point because we have a fair amount of points to go through. So in that GitHub repo, the bit of code that we copied, which is this SQL statement, what this is going to do is it's going to create a special timestamp function for us that we'll be using for our update and our created at abilities so that we can be notified if there's an update behavior every time something happens. We have a table here that is going to be simply creating a unique ID, which is an incrementing integer. Don't do this in production. Utilize the built-in UID functionality we have or something that would be a better approach. But for a demo and for a workshop, we're going to keep this rather simple today. So we can see here the total columns we have. We have a password column. We have an email column. We have a name column, created that, updated that, and then the ID. So fairly standard stuff. You don't need to understand what it's doing to be able to paste it in here. And we're going to go ahead and I think I need to zoom out to get rid of that database pop-up. Whatever. Let's go ahead and run that. And we successfully executed the SQL statement. So now what we should have, if we go up to the top here, if we click back on our public schema, we'll see that we have an untracked table or view. In this case, we're going to go ahead and hit track or track all. And this is, again, where Hazura kind of shines is because you can bring in a database from somewhere else with a lot of tables and you can come in here and manually track those tables or you can track them all and you will get an immediate GraphQL API sitting on top of your data. So we see these columns here, name, password, and whatever else. If we go to the API, just to verify that it's all working here, we can come in here for a query and we can say something like user and name, and we were able to query that. Now, it's empty. So it's not going to be particularly interesting to observe at the moment, but this is how this works. I'm going to take a quick pause here. So we've been going for about 30 minutes. Is anybody needing a moment to catch up? Is everybody tracking with what we're doing? Is anybody stuck? I'm just looking at all the chats. I am the last person to have written in both chat forms. So it seems like everybody's doing good. All right. So I think it's a bit too fast, says somebody. Okay. It's fine for me. But we want to work with what everybody's able to follow. Now, here's what I'm going to be able to say. Lagging behind with ng-rock. Okay. Leah, do you need the code? Or what's the issue? I can provide the code snippet if that's helpful. I can do that. So let me just go ahead and grab... Actually, I remember what it was off the top of my head, which does not happen with most code. So it's going to be pretty straightforward with ng-rock, followed by the protocol you want to connect on, followed by the port you want to listen on. So here it comes into the chat. It's basically that command right there. And if you are on a Windows machine, I'll have no idea what to do to troubleshoot. But it may also be something where later on what we'll do is connect a... Well, connect... Publish it to like a Versal or something and then not even do this as a port to your machine. So there's workarounds here if this is still a problem. But let me know if you're having issues there. What we'll probably do, because we have breakout rooms, we'll probably do at the 45-minute mark, we'll probably do a short breakout room, like five minutes or so. And then allow everybody to be able to see what's going on. Maybe everybody can help each other for a few minutes to catch up. And then we'll do a 10-minute breakout. So that's 15 minutes away. Now, the person who said it's going a bit fast, is that just me blabbing too fast? Or is that the actual progression too fast? Because both are possible problems. But I'm going to assume maybe it's a bit of both and just try to slow down. Good. We're all caught up. Very good. Very good. So we're going to go ahead and move on to the next step, which is now going to be fleshing out our GraphQL API to be able to give us resolver endpoints. So I think I totally skipped explaining what we're building. We're starting with a very basic user authentication system. I think I mentioned this in the workshop description, but user authentication system, we have a table with users, and then we're going to have a login and a signup action on that API. And then that is going to give us an authenticated token that we'll be storing inside of a protected cookie. And in that protected cookie, we're going to be able to send that to authenticate our requests from our client. And hopefully, if time allows, and I'm feeling pretty good about it, we're going to wrap this all up inside of an easy peasy, which is a library, easy peasy state management hook utility that will allow us to be able to sort of have a persisted user state mechanism. Now, this is not all code that I came up with.

7. Creating Login and Signup Actions

Short description:

A coworker named Gavin Ray helped me revolutionize the way I build applications. Hazuric Cloud is great for M1 Macs. Now let's continue with the actions. We define a new top-level field for the login action, specifying the input and output types. We also define a handler to resolve the action. The handler's URL is based on the action base URL and the file structure of the project. We create the login action and proceed to create the signup action.

A huge shout out to a coworker of mine named Gavin Ray, who helped me with a lot of this, and I've kind of broken it down into some more smaller bits. But this is something I think kind of revolutionized the way that I build applications.

So all right, so very good. Okay, let's go ahead and ngrok doesn't do the auto suggest the correct binary. Yeah, also on an M1. Yeah. Yeah, that's a fun development experience. Another reason why Hazuric Cloud is amazing, because the Rust and Haskell that's running Hazura engine doesn't play so nicely with M1 Macs. So if you really like Hazura, Cloud's a great way to work on an M1 Mac. Just putting that out there.

All right, we'll go ahead and continue on with the actions. So we're going to go ahead and move to the actions tab. Let's have a quick look at the bit here that we have. So we've got the tables created, and our users created. Coming down now to create actions. And we've got add login actions. So GraphQL code, which we need to be doing here. So we'll start off with our login action. So I'm going to go ahead and hop back over to my close down this tab. And now we don't need to be here. We're going to go ahead and go to this actions tab here at the top of the Hazura console. And I'm going to go ahead and hit create.

Also, I've been selling Hazura Cloud pretty hard, because I'm just a fan of it. But this is all open source code. This is all open source stuff, too. So if you want to run this on Docker on your machine or on your own infrastructure, go for it. This is the same product, except for the monitoring and a couple of the server level optimizations. This console, the setup, the interface, everything is all part of the open source product as well. So if that's your cup of tea, do what makes you happy.

So here, what we're going to do is we're going to define a new top level field on our mutation that is going to be a login action. And I have gone ahead and written that code out that we can just copy and paste. But it's pretty straightforward. It's not something that's terribly difficult to kind of grok. But if we just paste this in here, so we have the top level mutation type, there are two top level or three top level types inside of the GraphQL ecosystem. You have subscription, mutations, and queries. Mutations are your CRUD operations other than read. So create, update, delete. And then we have the login is the name that we're adding on here. Now, what we're going to do, and problem number one, I just realized I have to fix as well, is don't call this input. Because the code example that I've written elsewhere is expecting this to be called params. So we'll do login params. And then we have this login input and a JWT output from this GraphQL SDL here. Now, we're going to go ahead and grab those because I've written them here as well. And let's just paste them over and talk through what they do. So what we're doing is we're telling GraphQL here that we have these custom type definitions. This login input type will be expecting a signup. Am I doing login or am I doing signup? We're doing login. Okay. So the login input type takes in the email and the password of the user. And then it is going to return a JWT, which is going to be an ID, a name, an email, and it is going to be the token itself. Now, to be able to get that data and figure out how or what's this data supposed to look like, we need to have a handler that's going to actually work with this content for us. And that's where we define that here at the bottom. And this is where all this whole ng-rock stuff has been a thing is that we need to be able to define where is this handler, where is this resolve taking place for these actions. So in my case, I'm going to go ahead and steal the bit of code again from GitHub. And I've got it just right here for the login action. And we're going to paste that right over inside here at the handler area. And so what we've got is a parameterized string interpolation here. So this is the action base URL that we defined at the very beginning, the variable. The reason why we had to do that at the beginning is if you give it a name that doesn't exist here, it won't save because it needs to know what to give it. Even if you give it a dummy value, it needs to know that environment variable exists, otherwise, it's a no-go. All right. So we have the action base handler, and then we have the API forward slash API forward slash actions forward slash login. That is simply how I have broken down the code structure for my Next.js project. If you're not familiar with Next.js, again, we will be getting into that here very shortly. You have underneath the pages route, so anything, any file under the pages route gets converted to an actual route for your application. Anything underneath the API folder becomes a server route. So it becomes, it only executes on the server. It's not accessible from the client. And then from there, you have free choice. Because these are actions in Hazura, for a nomenclature, I've decided that forward slash actions and storing everything that I am mapping to a Hazura action for just code cleanliness and clarity, I've put in a subdirectory called actions, and then this particular one I'm calling login because the action is called login. So not breaking the bank on creativity here, but this is just sometimes for me as a developer, I get stuck on this kind of stuff. And I kind of think, oh, this is like a magical string. Is there a reason why it's named this way? Will it break if I change things? No, you just got to map up where you put the file with where this path is. So this is just simply why I've named it this way. And maybe I'm the only person that gets stuck on that stuff, but there you go. So we have the handler identified. And again, there's nothing running here. There's no code running there. It's not going to do any checks. It's just saying I'm going to call that URL when somebody calls this login action. Go ahead and hit create. We've made the first login. Very good. So now I'm going to go and make a new action here. And we're going to make this be the signup action. We're going to go back over and just snag our code again. So we're going to do the same thing here, the signup. And I want to use clipboard magic here to do multiple things at once. And I'm going to go back over into the I hope that's not like you're seeing this Zoom screen share stuff popping up all the time. How annoying.

8. Handling Signup and Login Actions

Short description:

To handle the signup and login actions, we need to rename the input to params. We can omit the JWT declaration as it is already in the system. We can also forward client headers and define a custom header for security. After creating the actions, we need to open up the permissions for anonymous users. Once permissions are set, we can test the signup action in the API Explorer. However, we still need to address the issue of not having an endpoint running at the resolver. We'll proceed by creating breakout rooms for further discussion and then move on to the next step, which involves setting up the handling of the API endpoints using a Next.js application.

So I'm going to go ahead and paste in on this new action here, which is in my case, the type mutation signup. Again, we need to rename that from input to params. And again, that's because the code that I have existing is expecting params. You could call this whatever you would like. This is again, it's not a magical string here. And I'm going to go ahead and paste in the signup input. Now I'm going to omit the JWT because any type you create is global. And so I know that I have a JWT type already created. I could inspect it underneath the custom types tab here as well. But since I know that I have one, I don't have to read declared here. In fact, I would get an error if I did. So I'm going to go ahead and leave off the JWT declaration. Because I have it now in my system. And I will have the signup input declared here at the params endpoint. And we'll just paste in the signup handler right there. So I hit save.

A quick conversation about what this kind thing is. Synchronous means this is blocking IO. So it's going to be run the thing, expect it to come back, set a timeout if you need to. The other option would be here is if it was asynchronous, it would bring back a process ID. And then I can subscribe to that ID for when that completed. For signup, we're not going to worry about that. We're going to just stick with the basics today. So that's why we're doing that. You could forward the client headers if you wanted to. So you could say basically anything that maybe my client is passing on. Perhaps I have a custom action I've authenticated with a CDN or my CMS or some other utility. And I want to be able to get credentialed data that my client is maybe authenticated against Fitbit, for example, as a web app. And I need to send that token along with this resolver request to be able to get some protected data from my handler, if that's possible. I could forward that along with the request here by toggling forwarding client headers to webhook. And then I could also define a custom header here. So I had a special key that I needed to provide. This is not a bad way to provide a poor man's security handshake between this action and your resolver. Giving it a special header here to say something like, you know, secret key is 1234. And then in the action handler, be able to check, hey, only my action should be able to request this, right? So that's not a bad approach to go. Y'all smart devs. So I'll let you figure that part out. So we're going to go ahead and create this here. And what we have at this point, then, is we've created both of these solutions. The last step I'm going to do here, and then I'm going to switch this into a quick breakout for 10 minutes, because I just want to give you all some space, is we're going to go ahead and open up the permissions on these two actions, because they need to be unprotected endpoints, right? I'm not logged in, if I'm trying to log in. And I'm not logged in if I'm trying to sign up. So they need to be accessible to our anonymous role that we created. So starting with sign up, we're going to go ahead and go to permissions. I'm going to only have to type it in once here. So again, that's a magical string matching to the name of the anonymous role that we created at the very beginning. And so now we know that this is accessible to an anonymous user. And then we're going to go to log in here, and we're going to see that the permissions tab already has anonymous not entered into my roles table. I just got to go ahead and hit update on this one. And now this is also available. But go back to my API now to the API Explorer, we'll see that if I were doing a mutation, and I do something like looking for a sign up, I now see that I actually have these sign up actions at the top level of my API. So we have the name, we can go yada. And then we'll go email. And we'll do something like yada at YOLO.io. So I'm sure there's got to be a YOLO.io. Apologies to them. And then we're going to pass in the password, which would be like 123. So and then with GraphQL, I got to give it a return type, which would want to just grab the ID and the token. Now, obviously, if we go ahead and run this, we're going to get an error, because we do not actually have an endpoint running at that like resolver. So that will be what we start to address next. I'm going to go ahead and break this up into breakout rooms for we'll give it five minutes in a breakout room, not 10. So I think everybody should be pretty well caught up. But we'll do that. And we'll see how that works. So first, I have to figure out how to do breakout rooms. And I saw the button earlier. We have to stop sharing first. So I'll stop sharing. There's a breakout rooms button. So let's go and try it, see what it does here. So I'm just gonna randomly throw some people. All right. All right. I think everybody's back. So I would be curious to hear in the chat if that was actually helpful or not. So let me know. Because I don't have to put people into breakout rooms. But maybe it was helpful. So we're going to go for the next, the next stretch here. And ah, somebody was all by themselves. That's, that's terrible. Yeah, okay, I'll try to have a better eye on that. And also, I'll try to visit each room next time as well. I had to get some water because of the pipes. We'll just pretend that's water. All right. So we're going to go ahead and move on to the next step now, which is where we left off. I think I need to share my screen again here. Where we left off was getting the actions to show up inside of the API. Now we need to go about the setting up of the handling of those API endpoints. So to do that, we're going to create a Next.js application that will then handle this code.

9. Setting up Next.js Project and Dependencies

Short description:

Now, let's create the Next.js project by running the NPX create next app command. We'll also install a set of dependencies, including bcrypt, next connect, Apollo Client, cookie, easy peasy, env command, GraphQL, JSON web token, JWT decode, React JWT, subscription, and subscription transport web socket. Additionally, we'll add the GraphQL Zeus library, which generates typings and a local SDK for GraphQL endpoints. GraphQL Zeus provides a structured and predictable way to query content and creates a tight coupling between the GraphQL server and the front-end code. While GraphQL Zeus has some negatives, such as teaching a new way to write queries and lacking documentation, its typed nature helps with faster development. Let's proceed with the project setup and dependencies installation.

Now, I'm trying to think where the best place is to paste large portions of code. The first, the first phase here. Yeah, we're going to do it this way. So, so take, make sure you have access to that GitHub repo. And the first, the first bits of code are going to all be in there already. And as we go, I am going to paste it once inside of the project and just push that up. And then the second is I'll be just pasting it into the actual project that we're creating together. The one that we're doing from scratch as a follow along from the tutorial here. So again, most of the code is already existing inside of the GitHub repo. But we're going to do this together here.

So the first thing we're going to do now, so we've gone through adding in our handlers. And we've added the permissions layer. So we're on to creating the Next.js type project. So you'll want is the NPX create next app at latest dash dash TS followed by project name, which is again, whatever name you want it to be. That NPX just says execute this command from the NPM library without installing anything. It's a global to great utility. The latest just make sure that everything is happy. And the dash dash TS makes this a TypeScript project. So we're going to go ahead and start this. I'm going to open up a terminal here. And if I have my terminal, I do have a terminal up in that terminal. So we're going to go ahead, I'm just going to navigate my way to my development directory here. All right, and inside of the Azura, and we're going to go inside of my workshops. And I'm going to make a new project in here. So this NPX create thing, and I'm going to just go ahead and call this one again, the RA dash Jesse workshop. And that's going to ask me just a couple of things here, I think. Normally, maybe I've already agreed to things in the past. So what we should have now, if we see the CD into that, so we should be able to CD into the RA workshop. So if we just do a quick LS on this, let's go ahead and make this a bit bigger here so we can kind of see what's going down here. I'm just trying to make sure I have an eye on chat real quick. The chat window escapes me at the moment. Where's the chat window? Is it somewhere? I think I've misplaced the chat window. I've still got my eyes on Discord, but where did I put chat? I'm welcome. Welcome to 2021. There's chat. I see a little red bubble. Yeah, thank you for adding a little color pop there. I don't know why that window disappeared on me, but there you are. Very good. So thank you. Good. What we have here is the basic project where you're going to go ahead and install a big old bash of dependencies to get moving. So if you go to the Git project and you scroll down just after the command, you're going to see the dependencies, and I'm going to go ahead and just copy them here, and then I'll paste them and talk them through inside of the editor here. So let me just zoom in again here a little bit. What we got going on here is we need the bcrypt library. We need the next connect library, which handles typings for the next JS API routes. We're going to be using Apollo Client later on. The cookie library, which is going to help us be able to work with our cookies really easily. Easy peasy state management. Env command allows us to run credentialed package JSON scripts. GraphQL, which is a general utility that Apollo relies on. The JSON web token. Can I scroll down? Here I can. So JSON web token, which is going to be another utility that allows us to be able to read values from the JSON web tokens. JWT decode, same thing. React JWT, same thing. Subscription. I can't scroll. I'll just do it this way here. Subscription transport web socket. If I get time to, we'll actually use the new GraphQL WS protocol instead. If we even get as far as adding subscriptions to our system generally, because this is technically a deprecated library. It is what you'll find in most of the examples. GraphQL-WS is the new one, which is pretty much a straight drop in with some minor, very minor adjustments. But we'll have a look. And then that's our dependencies that we'll need for this project. So let me go ahead and open up the terminal. We'll go ahead and run these first batch of dependencies here. The second step is going to then be adding in the dev dependencies. So we'll let that finish running here. And we're going to go ahead and drop that, which is going to be just some basic types support for the GraphQL types library. The one big one that is not actually part of the types library, or not a types dev dependency, is probably the most important one of all. And that is the GraphQL Zeus library. Now, if I didn't warn you already, this is a very opinionated way to build apps. The warning is coming. What is it now? Been about an hour in, we're at the warning that this is an opinionated structure. GraphQL Zeus is a really cool library that does a number of things. One of the very specific things that it does is it takes a GraphQL endpoint and it generates typings and a local SDK of sorts for those endpoints that allows you to query your content in a very structured, predictable way. And this creates the tight coupling or handshake between your GraphQL server and your front end code. Some negatives about GraphQL Zeus that people have said is that it's teaching you a new way to write queries. And yeah, GraphQL is already new to a lot of people. So we'll go over that and then see what they mean with that. Another one, this is my personal pet peeve, I find the documentation a little bit lacking. So that's like, it's an open source tool. So I can fix that, you can fix that. So I'm not going to complain about that one too much. It is just, it takes a little bit of trial and error, but fortunately it is a typed library. So you can oftentimes get things working faster by not knowing the correct way technically, because the typings tell you what to do. That being said, let's go ahead and look at back at our project now. So what we've got going on, back to the terminal that I just quit, which is less helpful.

10. Setting up API Secrets and Creating API Routes

Short description:

In this part, we open a new terminal window and continue with the RA-GSC workshop. We set up Visual Studio Code and start adding our API secrets. We create a new file called dot local and fill it out with the necessary information from our Hazura project. We grab the JWT secret and the admin secret. Our environment is now configured, and we proceed to the next step of creating the actual API routes and the subdirectory called actions.

I mean, open up a new terminal window and get myself back to that project. And that's the RA-GSC workshop. All right. So we have the product, we have the dependencies. We're going to go ahead and open up a Visual Studio Code, use whatever you want. I like Visual Studio Code because it does a lot of the stuff for me and I don't have to worry about it. So definitely pick your ID of choice, but I will be using this one. And from here, what we're going to do is we're going to start to add in, and I'm going to actually open this up in a side window here. So what we're going to do is move this over. So I'm going to be kind of flipping back and forth between these projects. And yeah, that's what we're going to do. If there's anybody who is going to have an issue with that in terms of motion reduction and things, please let me know and I will just switch back to a more subtle movement option. But I'm just going to try that for now. So if that bothers you, let me know. I don't want to put anybody into seizures. We're going to start off with is we're going to go ahead and add in our API secrets. So let's just go ahead and copy the bit of code here from the environment variables, and we're going to head over to the project here. And I'm going to make a new file called dot local. And we're going to need to fill this out here. So we're going to need to go back to our Hazura project. And we can get this in a couple of places. We can also get this from right here. We're going to grab the API, GraphQL API endpoint here, which is this one. And we're going to paste that down here under the Hazura endpoint, because you'll see that's the one that's post fixed with v1 GraphQL. So we're just going to use the full GraphQL address there. Now we're going to just snag the part up to the app for the next public Hazura URL. The reason we're doing that is this code base is designed such that you could very well have a dev environment and a production environment. And so you can pass in some different URLs here. I've reduced all of that for the purposes of this workshop so that it's a bit more easy and straightforward to reason about. But the code's there. And you can easily adapt to that need that we have material around that to some extent. You can look at the Hazura super app as an example. It's a huge e-commerce mono repo thing. As an example, reference architecture, a lot of this code comes from there just cleaned up a little bit. But that's why we have it this way. But the code base, you'll see some places where things seem redundant. That's because it was intended that you could do things like dev environments.

All right. So what we have here is the Hazura admin secret. We need to grab that next. I'm going to fill that out last, actually, because I'm going to spend less time exposing that. What we're going to do is grab the JWT secret, which if you'll recall, we snagged from the readme of the GitHub repo. So that is going to be exactly this string from up here, because this is what needs to check out front and back to the server from Hazura to be checking from the server. We're going to snag this one right here and head back over and we're going to go ahead and call that the JWT secret here. And then for the admin secret, we go back to the console. Wish I knew how to get that thing out of my way. Is there a way to dock it to the side? No. I don't know. Sure. Whatever. No. Good. Fine. If anybody wants transcripts, I think I could turn on transcripts. Just let me know. That would be helpful. Then reminding me where I am. Okay. So we have that. And now I need to get the admin secret. There we go. Catching up. It's getting a little bit later over here. I'm old. That's fine. Admin secret. We're going to go ahead and just copy that from right here. And we're going to paste that in right there. And close that window. So our environment, our.env.local is created with the values that we need input. And I think they are rather self-explanatory. But you can have a look. I'll burn that token later anyway. So if you need to see it, let me know. I can show it to you. I'll not know which one of you ruined the workshop. That's the problem. That's the only sad piece. All right. What we have now is everything else is configured. Let's go ahead and see what the readme tells us to do next. The readme is over here. So we're going to go to the readme. And we've defined our environment secrets. So now we're up to creating the actual API routes. And now we're getting to the actual next JS bits, TypeScript bits that are a bit more specific. So you'll see the structure here that we need to follow inside of the pages path. And I'm going to look at this in a minute. Inside of the pages path, we're going to need an API subroute that exists with this scaffold that you already created. And then we're going to add another subdirectory called actions.

11. Setting up Login Route and Code

Short description:

We're going to start with the login route. I'll show you where to find the code inside the GitHub repo. Inside the front end complete folder, go to the pages path, then API actions, and inside the login file, you'll find the code. Copy and paste this code into the login.ts file under the actions folder. Let's discuss what's happening in this code and address any issues.

And then we're going to give it the actual resolvers that we needed to do. So what we're going to do is we're going to start with we're going to just do sign up and log in at the same time. And we're going to do the we're going to delete the dummy one that they've given us by by default.

So underneath the pages route here, we're going to go underneath the API folder. We're going to delete this version here, this hello.ts. It is one for helpful code, but I have some code written for us that we'll have a look at. So we'll just know about right now. I'm going to go make a folder under here called actions. And inside of actions, we're going to go ahead and get our first one, which is going to be called login.ts.

All right, so what we're going to do here is I'll show you where to find the code inside of the GitHub repo. And then I'm going to go back and I want to just do it from what I have here locally. So inside of the repo, if you go to the front end complete folder, that will be complete. And you go to the pages path and you go down to API actions, and you go inside of the login. Here's the code, right? So this is what you're going to copy and you're going to paste right over into the different actions that are named the way they're named. I'm going to snag mine from over here, because I have the same thing open locally. And this is where I'll be pasting the content and posting it up as we go once we get to the pieces that I have to copy and paste from somewhere else that's not currently available. So we're going to just work with that structure. So I have the pages, I have the API, I have the login. And we're going to start with a login route. So I'm going to copy this and then we're going to do a little talk through about what's going on here. And we're going to see a lot of issues. So we're going to see what's going on here.

12. Creating Login Behavior and Cookie Utils

Short description:

The vCrypt library is an encryption library used in this login behavior. The NextConnect API handlers allow us to map the NextAPI request and response typings. The handler.post function handles post requests to the login path. We query the users based on the email and return the ID, name, email, and password. If the user doesn't exist or the password is invalid, appropriate error messages are sent. If the login is valid, a JWT is generated and set as a cookie. The token, ID, name, and email are sent back through Hazura. The front-end communicates with Hazura through API routes and actions. The code for the login behavior is provided. We will add the necessary files and test the signup handler next.

All right. So the vCrypt library, it's an encryption library. This is not an encryption conversation. So don't ask me a lot of questions about it. We'll look at how it's invoked, but we're not going to really, yeah, we're not going to go into it. We have the NextConnect API handlers. This allows us to be able to map the NextAPI request and NextAPI response typings, which is really helpful for us to be able to actually get us to use Connect-style middleware.

So we have then this idea of handler.post, which is going to be handling post requests to the login path. There are other ways to do this. You don't have to write it this way. This is just the way that is helpful because a lot of people are used to this Connect-style router logic. So what happens is the request comes in. We do a little bit of console logging because we're professional developers and that's how we do debugging. And then you have the email and password that we're reading off of the login route, off of the login input params. So the input is what Hazura calls everything that it gets as an input type. And then that params is that key that we had in declaring our custom type for the login. So when we change everything from input to params, that's why we did that because I just got a little brain goof. So input is what Hazura sends. Whatever is being passed as an input from that point is what's going to be what you read off of the actual request. So it's the input and then the params or whatever we wanted to call that, we can call that there. So we're getting the input params from email password. And then here we are using a client, which we're going to create in a minute, that is going to query. And this is the GraphQL query, but this is the one where it gets a little funky, right? So we're going to query users where the email is equal to the email pass here. And then we're going to go ahead and say return the ID property, the name, the email, the password from our user. And what we're going to do from there is then we're going to say, okay, if the user doesn't exist, go ahead and throw it back in their face. And then we're going to say valid password. We're going to compare the password we're getting from the login attempt with the password we have stored. These are encrypted passwords. So that's what this bcrypt compare is doing is it's taking in the string value plus the encrypted value and then it's taking in what it knows is the encrypted value and it's going to go ahead and compare those to see if this is actually a valid login. If it's not, it will also send back an invalid thing. This is where you get accustomed with your error messages if you wanted to. If the user gets down there, they have a they exist and their password is valid, then we're going to go ahead and generate a JWT for them, or we give them a default role of user. This allowed roles is a security thing where basically you could say that only the roles are only allowed to be one of a defined set here inside of the allowed roles. And then the XHazura user ID will be set. This JWT gets set as a cookie, the Hazura user token. This is that JWT object that we put inside of our environment variable. So saying this cookie will be sent back. It will be HTTP only, which means you can't read it from the client. And then it will go ahead and send it back a secure, give it a time to live, and set some various parameters. These are all magical invocations that nobody really understands what they actually mean. This set works. So just you're welcome. Cookies are a weird dark art. So yeah. That was fun to debug a bit. So anyways, then we have the return from the response that goes back to the Hazura action handler. So then we're sending back the token, the ID, the name, and the email. So if you remember the type that we identified as the JWT type, this is the JWT type. It has a token, it has the ID, it has the name, it has the email. That's getting sent back back through Hazura. So it's a little bit of a mental twist here to just kind of know that our front end isn't really talking to our API routes in terms of like, well, you're kind of co-locating logic. So you have like a page here. What's actually happening is a request from that page is going to Hazura. You can get down on the camera here. Going up to Hazura, hitting an action, coming back down to the API route, going back up through Hazura and back over to the user. And this is just a way for us to have an authenticated layer because this client might be, our handlers could be somewhere else. We could do a low code solution. We could do a Lambda somewhere. The fact that we're doing our code here inside of the API routes for our action handlers is totally neutral. It doesn't matter at all in terms of what we're actually trying to accomplish. So just so you know, like that's kind of what's happening here is that they are technically separate purposes. So don't like worry about that too much. So anyways, that's kind of either here or there. And the rest of the code here is just basically make this work, telling it that it's supposed to parse the body. And this is the handler. So this is the login behavior. Now, you'll notice we're getting a number of errors here. And we're going to go ahead and actually add each of these files one by one and talk through what those pieces do. And then we're going to go ahead and add in our signup handler. And once we've done that, we're going to test that it works. And that should be where we're at. Okay. We're going to move on to creating these files in order from top to bottom. So we're going to go ahead and create the cookie utils. Again, this is in the GitHub repo. So you should be able to find this no problem. I'm going to go ahead and go underneath a folder that doesn't exist yet that I'm going to create at the top level here called utils. And inside of utils, I'm going to go ahead and make a cookies.ts. And that cookies.ts, I'm going to copy again from over here. And I'm going to we're going to talk through what this is doing. So this is just a very simple two methods here. Where it's going to go ahead and essentially give us a serialized cookie statement. Cookies need to follow a very specific format with serialization and everything. It's just helpful to have that in a wrapper. Because string concatenation is not always fun. So we're going to go ahead and add this in here. So we have this set cookie method that we're going to be able to pull off on it that allows us to essentially just create a valid cookie header that we send back from the request object. There's nothing very fancy here. This is just simply what we're doing. So we're passing in a response object, the one from Next.js.

13. Setting Cookies, Utils Client, and Generate JWT

Short description:

We're setting a header on the response object with a valid cookie string. Then, we have a destroy cookie function to handle cookie destruction during logout. The utils client file handles server-side and client-side calls, passing the appropriate headers. The generate JWT function is a wrapper for the JWT utility, creating a valid JWT token. These are abstractions over basic web technologies like setting cookies and generating JWTs. Next, we fix an issue with the client file and add a magical string to the library.

We're setting a header on that response object with a valid cookie string with the parameters that we want it to be. It's, again, a bit of a dark art. So don't worry about this too much. This is just a way that this is a way to write this kind of cookie setting logic. That's all it is. It's a cookie setter.

From there, we have later on, which we'll be using is a destroy cookie. This allows us to just set a unified approach to handling our cookie destruction for when a logout behavior occurs. Because people do that. They log out of applications. So we're going to go ahead and support that as well. Okay.

Cookies are created. We'll go ahead and save that. We'll go ahead and close this file down. We've looked at the cookies. Now we need a utils client. And in this client file, this one is a little bit funky. And that's because this was designed for that ability to do protected. It's a bit of a cheater. And I have a note. I was cheating on cheating here. So I have a TS no check on this, which is helping me be able to get around some issues. Because I haven't been able to debug this one just yet. But the behavior here is saying, if I'm calling this client from the server, go ahead and pass in my Hazura admin secret. Just as a general, like, all my server side calls are allowed to be done with the XHazura admin secret. Because I know that's a protected execution. If not on the server, because Next.js has that dual execution paradigm where I can do things on the client or on the server. If I'm not on the server, don't pass in that header. And that's essentially what's happening here.

It's also got this idea of a of the client and an open client. And with the open client, it would be saying, if I had potentially two different APIs or I had two different versions of my API that I never wanted to have this be credentialed, I actually don't even think this demo uses open client anywhere. I have left it in there. But it's just a way, if you had a lot of dev environments or other ways, different kind of API wrappers for production versus development versus whatever else, these methods would help you be able to support that. It's boilerplate code. You could probably get around not even needing it in most cases, because all of our calls are essentially authenticated. The only two that are not authenticated are the ones where we're calling the client from these sign up and sign in areas. You could just pass in the admin secret directly in there and not even need this utility. It's just a helpful utility to have as a pattern. So that's about all there is to say about this client file. If there's any questions on that, let me know in chat and I will definitely be able to break it down more. I'm just skimming over the parts that I believe are less interesting to just explain what they're doing, because they're neither here nor there in terms of functionality. It's just a pattern to use that you could use anything.

Generate JWT. This is going to be the last helper that we're pulling from before we need access to our actual SDK. So what we're going to do here is underneath this utility, we're gonna make a new folder here called off. And that's just because if we wanted to follow some other paradigms besides JWT, maybe we could do that. But in our case, we're only doing JWT. Again, this code is inside of that path. So I'm going to go ahead and go to the complete example. Actually, I'm going to copy it from over here. Off JWT. Let's have a look at what this one's doing here. Okay. So what this one's doing is it is creating the... Yeah, it's a wrapper for the JWT utility that's just creating a valid JWT token. If I had other parameters I needed to pass in, I could do that. Most of this is TypeScript wrappings around the JWT utility. It's got a default value here in case somebody was not passing in a secret as they should. Happens to match the same secret that I'm using. But this is just a default value in case somebody had omitted that from the environment setup. So it's giving us a bit of security here, as well as then the default configs. And I can delete this. This is... It's actually nothing. That was a Git debug attempt earlier. And then I have the interface for what generate JWT params should do. And then the actual generate JWT function. So abstractions for basic web concepts that you could totally inline in your code or you could work with abstractions like this so that if you needed to pull this into a library or set up something, you could do that. These are... That's really all these are. It's just abstractions over basic web technologies, like setting cookies, generating a valid JWT shape, things like that. That's all these are. So don't give them more brain space than that. I know for most of the team who do demos and things, these bits of code have migrated from project to project to project because it's just worked and they just take them. So yeah, it's not like an extremely delicate, dependent way to work. Okay. That takes us up to basically the most important part of all. So if we go to client here, we'll notice that this is where we have the issue for the moment. You'll see that there's no generated file here. So we're going to go ahead and fix that now. If we go back to the GitHub repo and have a look at the next bits of code on the README. I'm going to go back here to the README. What we have here now is we've created the the first API route. We haven't created signup yet. We've got login going right now, deleted the hello, and we're not going to worry about the signout. We might do signout in a second. But what we need to do to make this continue to be finished valid is we need to add this bit of magical string here to our library. And I'll walk you through very carefully what this does. It's not fancy.

14. Using the Zeus CLI to Fetch API Data

Short description:

The Zeus CLI is used to fetch data from the API, providing both Apollo typings and TypeScript utilities. The.env file is used to configure the endpoint and other parameters. The generated folder contains the Zeus folder, which includes an index.ts file. The index.ts file contains the typings for the GraphQL API, allowing for easy querying and access to the API's available data. This provides a way to know the API structure without running any code. Errors are thrown if changes are made to the Hazur cloud project. Issues with the.env file and endpoint naming are addressed, and dependencies are installed. A workaround is provided for Windows machines. The SDK is rerun, and the generated folder is created with the Zeus folder and its contents. The index.ts file contains the API typings and client wrappers for fetching data based on those typings. The IDE is aware of the API structure, providing helpful features and error checking. Debugging is done for potential issues with the.env file and endpoint naming. The nth command is suggested to be removed as a fast workaround for Windows machines.

It just is long. So let's go ahead and have a look at it. What this is doing is it's calling the Zeus CLI to give us to fetch from our API the data we need fully credentialed so it has full access and bring us back both the Apollo typings and the general TypeScript. I want TypeScript and I want the utilities for Apollo. So env command grabs the.env and I'm actually thinking that I may have a bug with that. We'll find out because I don't think env command likes.env.local as the name convention for my.env file. I'll have to check that here in a second if it complains. But take that in, go ahead and do string interpolation on what follows. In that case, it's going to be the Zeus command passing in the endpoint which I need to rename here. So make sure you're catching this part. You'll need to do hazura endpoint. Because I renamed that in my.env file. Hazura endpoint and then we have the utils. We have the utils generated as the folder that I wanted to go into. And then it's passing in what I want to be pulling out of it. So Zeus on my hazura endpoint. Pass all of what you're going to create into the utils generated folder and then use the Apollo basically generate the hooks and handlers with TypeScript support. Here's the header you're going to need. My hazura admin secret. Here's a credential value. So it's pulling all of that. And this is my graph QL SDK. This is the handshake that holds it all together. Let's test this. I actually think it might fail because of that.env.local. Let's just give it a quick test here. We have failure. And I'm guessing it is because of that.env.local. Let me just yeah, fail to find.env file. So let's go ahead and just rename that real quick into.env. And when we do that, we're also going to need to just rename I believe because this is an XJS project. We're going to have to just let Git ignore know that we actually have an env file that we want to not include because otherwise it includes.env by default. If you use those as important globals for the server that you can check in the repository, but local and whatnot is ones that you don't want to. They've got a whole theory behind it. Good for them. Okay. So we're going to go ahead and terminate this process. And I'm going to go ahead and run that command again. I've got this funky keyboard binding here that likes to fight me. I'm going to go back to package JSON. All right. So we're going to go ahead and run that script. And we'll see that it did actually go ahead and work. So we have the generated folder now created if we go inside of generated, what we have is the Zeus folder. And inside of the Zeus folder, we have an index.ts. We have a const. We have an Apollo. Now I'm going to open up the index.ts just so you can see it. And if you'll see the mini map here on the side, like I'm glad I don't have to write this by hand. Like that's a lot of typings to get and a lot of funky typings. So let's talk through what the different pieces are here just so we understand them. Index, this is the typings from my GraphQL API. So it's pulling down everything. The user model that I have created, all these different pieces is pulling them down and it's giving me some helpful client wrappers that allow me to fetch based off of those. And that gives me the things like types. If I go to my log in handler here and I didn't want to, like I didn't have a password, you know, as a response here, I can do the typings and be able to see, oh, I got password here as an availability on my on my API here. And that is super cool. Like I have this ability to now know everything that my GraphQL API has available. And I'm not running any code right now. This is literally just in my IDE. It's aware of what my API looks like. And I make any changes to my Hazur cloud project, I come back here, I rerun the SDK, my product is entirely aware and it's going to throw errors if I've changed something. Yeah, you did the yeah, your problem is, Ktorik, is that you copied my code and my code is wrong. You need to make it be hazura underscore end point because I needed to fix that. It's this one. If I go back to show package JSON, you'll see that I changed it here a moment ago. Let's go ahead and just capture this for generations to come. And I'm going to just fix that as we go along here. So, we'll just do that there. And then I also had that bug with the word input that we're just going to fix as well to the rams. So, yeah. Good. Sorry about that. Error. Hazura endpoint now. Did you okay. Did you set that did you install the dependencies? Because you needed the nth command to make sure that it would do that good. Do you have Hazura endpoint in your dot nth file? Of course. Are you on a Windows machine? Yeah, you're on your own. So, there is a issue with that. I believe. Let's go ahead and debug this real quick. Because you may not be alone here. So, let me go ahead and open this up. Because there was an option. The workaround, the fast workaround is just swap out all the you can check that. The fast workaround is you can just take out the nth command. So, where I have package JSON. So, you could literally just like let me just show an example of what it would look like. Let me grab that whole thing there.

15. Creating Sign Up and Log Out Routes

Short description:

To create the sign up route, add a new file called 'sign up' in the actions folder. Copy the sign up code and paste it into the new file. Rename the file to 'log out' and update the code accordingly. Push the changes to the repository. Check that the code was added successfully. Add the 'sign out' path by creating a new file called 'sign out.ts'. Copy the code for the 'log out' path and paste it into the new file. Rename the utility function from 'set cookie' to 'delete cookie'. Make sure the path is correct. Verify that the changes are applied correctly.

Put a com on it. So, you would just remove I'll call this the insecure version. Remove the nth command dash X. Leave it as Zeus. Go ahead and paste in HTTP endpoint blah blah. I guess your endpoint there, right? And then you would then instead of this here, you would just remove that. And you would say, you know, super secret password. So, you could totally inline like whatever your endpoint is. You could inline that right here. And your password right here. And just replace the whole string interpolation bit as well. That would be the fastest way. I'm just going to do a quick check to see if there is a solution. So, nth command. Do a search here to see if there's a problem with Windows machines. So, the one that I am aware of is cross nth I believe is meant to try and fix some issues in terms of the cross browser thing. I should have that as an alternative here in the documentation for those that are on Windows machines. Okay. Yeah. I'll look into it some more too to see if I can put on a nicer, you know, fix for that. But, yeah, just bear in mind if you check that into version control to make that be a private repo is only thing to bear in mind there. Okay. Good. And this is why I didn't use cross nth. It's still running. But nth command was good. All right. Good. Anybody else have anything stuck on? We can keep going here for the moment. So, I'm going to go ahead and remove this for now. Okay. We'll leave that there. So, if we go back now to our login file, everything here should be fine. If we go to the client, we'll see now if we pull off this node check here. This is what I was having the issue with is that this is the input parameters here. I just needed to get in there and debug the TypeScript. So, open repo, feel free to fix my crappy TypeScript. This was the easier fix for the benefit this particular bit of code was doing. But now it has found, you'll see the actual chain import. So, we'll just leave that there for now. Okay. So, we have the generated we're walking through what this does here. So, the index is all the types, which is really cool. And then the Apollo thing, what it does is it's created a bunch of these generics, essentially, for the Apollo hooks. So, if you're used to working with Apollo in GraphQL where you have used type, use lazy query, use mutation, use subscription, if you're used to those hooks, this has given you a typed wrapping on those, which is super cool. So, now you have used type subscription, used typed lazy query, used typed query, used type mutation. This is a utility that reads all of those index, those types from index, and gives us now a hookified version of that, which is magic. We're going to have a peek at that. So, that is super cool. So, that brings us then to cons, which is just some helpful utilities for them. Just basically string values and things, enums and whatnot. This should get us far enough to be able to go ahead and create the sign up route, which is going to be basically just adding a new route here. So, we'll go to the actions, new file. We'll do sign up. We'll steal the sign up code. I'm a little bit surprised how much my voice is frying right now. And so, we got that. And now what we've got, I'm going to go ahead and add in the sign out path as well real quick. Sign out.ts. Just so we have that here. And that is the first bit that I don't have added. So, I'm going to grab it from my backup code real quick. That is going to be here. Let me just grab it and pass it on. So, we have the and I actually call it log out. So, I'm going to rename that to log out. And before I paste it in, I'm going to paste it in here so you all have access to it hot off the press. And we're going to paste that in and just push that up. Which I may have to go up the chain, but I think it found it fine. Yeah, I think I found it fine. So, let's have a quick peek to make sure that you're getting access to this all here. If I go up to the front end complete. Looks like it came in just fine. Good. So, now pasting it in my code example. So, it is looking for the set cookie utility. Which is a carryover that I had removed. We don't actually need this one. I'm going to fix this here. No, it's not set. Yeah, it's not set cookie. What I want is delete cookie. I believe. Why is the typing there not correct? Oh, because I probably have a type on there. So, to go here to the cookies, what I'm looking for is destroy cookie. Okay. So, we're going to go back over to here. And we're just going to call this destroy cookie. And there we go. And it's unhappy because maybe my path is off here.

16. Testing the API and Inserting Data

Short description:

The typing didn't work, but we'll fix it later. Patch it quickly. Thanks to Adam Turner for the fix. The logout file was in the wrong spot. We can now test our API locally. The project is running correctly. We got a token from the server. Data was inserted into our database.

That might be why the typing didn't work. Yeah. That appears to be good. And we're going to need to put a no TS check on there because it's the same issue. So, we're going to go ahead and go at TS. No check. And I'll fix that after some debugging later on.

Okay. So, if you're let's just go ahead and patch that real quick to something that you're able to also work. All right. And that's on its way to y'all. So, if we go back now to the readme, let's see what we've got going on here. I'm just checking the various chats. It looks like everything should be good so far. Okay. So, there's some issues here. Okay. So, Jesse, remove the delete from the params. Somebody's got helpful advice here. Okay. Okay. So, somebody's got a suggestion here. Maybe this is the issue. This could be because I was I was going to solve it because I think what I was debugging or solving this a different way earlier. Oh, there you go. So, everybody say thank you to Adam Turner. All right. Thank you, Adam, for the fix there. So, we're going to go ahead and go in. The reason why that had gotten there was I was debugging that in a number of ways to try destroying a cookie, which is not as straightforward as you would think. And I guess the one that the functioning code I had got wiped or something. But whatever. All right. Look for the thanks, Adam commit for the functioning code there. But I also need to isn't it like fun watching me code live? Isn't everybody enjoying that? Appreciate the vote of confidence.

All right. So, here we go. We got everything in theory working. I'm curious why I think it's because yeah, so, the issue is I put the logout file in the right spot for you all. I put it in the wrong spot for me. So, I wanted that not to be in the actions folder because it's because I had the because it's not mapping an action in Hazura. Okay. At this point, at this point, if we go down here, we should see that we have the SDK generated. We have the different files created. Now we're able to actually test our API out. So, what we're going to do now is we're going to go ahead and bring up the terminal. And I got to figure out my funky keyboard map here. I have this mechanical keyboard. And I've mapped the escape key with a tilde. But like, it's got like four function keys. I don't know. I'm yeah. So, we got this thing now where we got we're going to go ahead and try running this project locally. We're going to go ahead and say yarn dev on this. And if everything is working correctly, what we should get is a running example at localhost 3000, which we have. Now to test this. So, ng rock is theoretically still rocking for us with our with our ports. And those ports are being mapped publicly. So, I need to find the terminal session that has that running here. I think it's probably there it is. Okay. So, I think somebody tried making a request to that. Somebody grabbed the IP address. They're funny kids. All right. So, we're going to go ahead and test it out now and hope nobody's deleted everything important. So, we're going to go to the Hasura console now. We're going to test this out now that our project is actually running. I'll see if anybody's freaking with it. No, it's good. All right. So, I'm going to go ahead and come in here to the API. This is a different one. So, here's the RHSC workshop. I'm going to go and launch the console again. I guess I did have it. I did write that out earlier. So, that was probably the same correct one. All right. Coming here inside of the API Explorer, we're going to go to the history tab. And I'm going to pull this mutation that we tested out. And we're going to try running it and see if we get data. Look at that. We got a token. So, here we have the actual token coming back from the server. So, we're a little over. We're almost... I have to try to remember what time we started. But we're doing good here. So, we got the data inserted into our database.

17. Creating Apollo Client and Setting Up Boilerplate

Short description:

We have a functioning application with a functioning API and the Next.js app set up. We're going to create our Apollo client and set up our boilerplate to use protected content. Before that, we'll create auth rules for our user. The anonymous user will have select permissions to view everybody's name. Authenticated users will see their own name and email address. We'll create permissions for select, insert, and update operations. Users won't be able to delete themselves. We'll also create a user for testing purposes. In theory, we should have access to everything in the Explorer, but we'll need to adjust the user token. We'll test the user query and check if the email is accessible. The Xsera user role will be used instead of Xsera user token.

You got an error, Max. Okay. I'm going to show this bit here. And then we're going to do a breakout room. And I'm going to go into each of the rooms and just check in with everybody to see if anybody's got any issues. So, we're just going to view the data here from my side. And then we're going to do the breakout rooms. And we'll see that we have Yala, who was added. And a very nicely encrypted password. Okay. So, it seems like everybody's got this going just fine so far. So, very good. We're just about to kind of start to see the really cool stuff coming together now. So, where we're at at the moment is we have a functioning application. We have our functioning API. And we have the Next.js app set up. So, what we're going to do now is we're going to go ahead and create our Apollo client and set up our boilerplate so that we'll be able to actually use protected content. Actually, before we do that, we're going to go ahead and create some protection rules, some auth rules for our user so that our anonymous user will be able to access everybody's name. And we're just going to let them see everybody's name. But then an authenticated user will be able to see their own name and email address as well. You can obviously abstract that data model as wide as you want to go. Maybe we'll see about creating some relationships later on and some interesting pieces around that. We'll see where it goes. We've got about an hour left of the workshop. So, we'll just keep chugging along here. So, if I share my screen again, I'm going to go ahead and share down to there. Let's go ahead and create some permissions for the user model. And that's going to help us be able to kind of verify who's authenticated, who's not authenticated and kind of test that out and make sure everything's working the way we'd expect. From here, I'm just going to open up the chat and make sure I get that still visible here. Got the monitoring tab. On my user table, I'm going to go to the permissions tab. And on this permissions, what I want to say is that if I am the anonymous user, I will have select permissions without any check. It's going to be wide open. But I'm going to limit it to just viewing everybody's name. And I'm going to make that be that only allowed to maybe get 100 or 100 or 25 users at a time. And we'll go ahead and save that so that they're going to be kind of limited. Now, on the user itself, we want to give them some more controls. So, for the user, we're going to give them the ability to select the they're going to be able to select with a custom check in the situation where the ID of the column or the table row they're wanting to select, the ID has to equal the parameter coming in of that Hazura user ID. So, the JWT is coming in that has the XHazura user ID on it. And if that ID happens to match this row, they're allowed to check or select that without any constraints. And we'll go ahead and not limit that at all. And we'll let them be able to select everything. And we're going to also let them be able to do aggregated queries. We'll say go ahead and save permissions. And we're going to go ahead and say on the insert, we're going to allow them to be able to do the same thing. So, what we're going to do is actually go back to select and we're going to clone this permission over to the insert statement of the user rule. So, it's going to take the same concept for insert. And we need to just tell it which columns they're allowed to get. And then on update, we're going to do the same thing. So, I'm actually going to go back over here and do the cloning one more time. User has on the update and we're going to go ahead and say yes. Now, I'm going to be that app developer that doesn't allow users to delete themselves. Because everybody loves that, having to email somebody, you know, to ask them to delete your account. So, we're going to go ahead and update the columns. They are not going to be allowed to update their own ID, though. And they're not going to be allowed to update the created at. Those are going to be immutable values for admins only. And we're going to go ahead and say that. And delete. Yeah, we'll just leave it off for now. But that's going to be what we're going to do at the moment. So, that's great. We're going to go ahead now and come back to my users, my APIs. Go ahead and make a user that I'm able to actually reference here on an easier basis. I'm going to go ahead and say that this is just actually me. And this is my actual work email. So, if you have a question, you can definitely ping me. And that's going to be my password. But that's not the password for my work account, just so you know. It is the password on my luggage. So, we'll go ahead and do that. Now, in theory, and this is one that I actually haven't done too much testing with. In theory, what we can do here now is we go ahead and click on the Explorer. We'll see that we have access to everything here, right? We have access to everything we would want just fine. Now, if I were to go ahead and take a turn off the Xsera admin secret authentication, and I were to say the Hasura user token, I pass that token in here. And I want to get the user. I'm going to give it a name here. We'll see that I'm able to get the users. But if I ask for the email, I may have to redo that user token here, because let me log in and get a new token here real quick. I'll do a mutation. I'll get this out of my way a bit so I can kind of see my keyboard a bit more. So, the email was jesse.hasura.io, and the password is 123. And we want the token back on that. Okay. So, I'm going to go ahead and run that. And I think I know what the issue is, why this is not working the way that I expect, because I believe the issue is related to the fact that the client here, go to the history tab and view that. Yeah, the history tab here is not allowing me to be able to destructure these headers for me. So, I'm going to go ahead and not do Xsera user token. I'm going to do the Xsera user role. I believe is the name.

18. Checking JWT and Creating Apollo Client

Short description:

Let's check the code base on the JWT we're creating for the login. We'll create the Apollo client, which will live in the utils folder. The Apollo client has its own set of idiosyncrasies. We have the get main definition utility for determining if we're attempting a subscription, mutation, or query. We also have the get hazard URL function and a constants file. The constants file contains the server-side and client-side URLs. The Apollo client is created using the HTTP and WebSocket links, depending on the environment. There is a TS node check that needs debugging. If anyone is a TS guru, your help would be appreciated.

Let me go ahead and check the code base on the JWT we're creating on the login. We are setting this value, and then also on the JWT helper, we are setting Xsera default role. Okay. So, what I'm going to do now is go back over here. I'm going to pass in this. I need to grab that ID at this point. It's probably ID3. I think I've created maybe just two accounts. And then the Xsera default role is user. And let's go ahead and view the explorer on that. I may have to pass in the where. May have to come back to debug this in just a second, because that should be giving me the value I'm expecting. Let's go ahead and make sure that my ID for my user is correct. Yeah, it's number two. So, I come back into here. Xsera user ID is two. Xsera default, double hyphen in there. I think I do. I shouldn't actually have a problem with capitalizations. I believe they are normalized. Let me fix this query here. Strange. What we're going to do, I noticed this bug a little bit ago. Maybe there's a problem at the moment with how it's passing in the values, because technically I should be able to select my own email with the validation. Now, if I run this from externally, what we'll do is a test. We'll run this externally from the client, and that'll be our client. And then we'll run this externally from the client, and that'll be our final test to see if that actually works the way we expect or not. Because it should, but I think there's an issue with it being coming from a cookie. So, I'm going to not waste too much more time on this at the moment. So, we'll turn that off for now. And we'll just get back to the client for the moment. But fully unauthorized user, we get just the names, because that's what we've told that. I'll just check the unless I did something really stupid. Did I reverse permissions? That would be amusing. Let's just check that real quick. I've got the admin secret turned on. Of course, I can see that password. Yeah. There we go. So, okay. All right. Let's skip that for now. Sorry for that little sidetrack. We're going to go ahead and have a look now at the Apollo client. So, we're going to go ahead and head back over to here. And the next piece that we need, and I'm having to reference this code that's now living offline here, is we're going to create the Apollo client, which is going to be living underneath the utils folder. Now, the Apollo client is going to be a little bit of a larger beast here. It may already be you already have it. So, I'm going to go ahead and steal this one from here. And it's going to live underneath the utils folder. Now, Apollo client with an XJS has its own set of idiosyncrasies. So, what's happening here? What we have is, you know, general imports from Apollo, the WebSocket link for subscriptions for later on. And then we have the get main definition, which is the default. And then we have the get main definition, which is the default. And then we have the get main definition, which tells Apollo, are we attempting to do a subscription mutation or a query? It's a utility for determining that. Then we are pulling in our get hazard URL. I'm going to turn off the note check here, because that constant is actually not created. I don't even know if I'm using it. I am in a couple of places, but we can bypass that, because we don't I will create a constants file. That's fine. This is part of the refactor I've been working on to get rid of this. But I have left this in on this version. So, I'm going to go ahead and just add this now. So, I'm going to go ahead and add a new constants file. And I'll show you what the code looks like here. That constants file is not the most sophisticated thing in the whole world. Where's the constants file? Did I switch sides? There we go. Here's the constants file. It's the exact same thing we talked about previously, where we have the server side versus the client side URL. Now, at the moment, if I remember correctly, I have refactored that away, that I only use the I only use the Hazura URL now. So, I even refactored this totally out. Which I wanted to use the, yeah, the app version. Okay. So, just totally removing that. I'm going to paste this over here for you to have access to. So, the constants file underneath utils. So, so, coming your way. All right. So, so, with this constants file, and it's being imported now inside of the inside of the, the Hazura URL function, what happens here, we get the actual Hazura URL. So, I was just doing a server check to say, okay, do I have a special version of my API endpoint for server versus for non-server execution environments? And then we are starting a, we have a Boolean check here for is it the server? And also one for the, if it's the browser. We have this utility here for do one thing if it's a, if it's a subscription. We have another thing, another function here that's a link utility that basically just says here's the HTTP link. So, use the Hazura URL, the GraphQL endpoint, include credentials, do the same thing for a web socket link if it's a web socket thing. And then in this, this Apollo link here, we're saying if it's a browser, go ahead and send, or if it's a subscription, go ahead and use the WS link. Now, I have the type, the TS node check on here because this, this method is got an issue with the behavior of the, the behavior of the passing in these two values. And I, again, haven't had a chance to debug that, but that's why we're going to go ahead and just block that out for now. But again, if anybody here is a TS guru, feel free to have a look at that. Because that will cause a problem for deployments. Just making sure that I'm still monitoring chat here.

19. Setting up Apollo Client and Fetching Users

Short description:

We have set up the Apollo client and initialized it in the App.js environment. We have also created a way to fetch users using the Apollo Hooks. Next, we will try to include the easy peasy bits if time allows. So far, we have successfully set up the Hazura project, generated the type SDK using GraphQL Zeus, and configured the Apollo client to work with our GraphQL endpoint. We are now ready to fetch content inside our React components.

Just making sure that I'm still monitoring chat here. So, good. All right. So, what we have here is the Apollo client. And what we need to do now is be able to take this, so, let's finish talking through what the code does here. So, it's giving us the right link if it's a browser. Then it's doing the actual Apollo client creation here. So, it's giving us a built in memory. It's telling us to include credentials. That's going to actually be what's the magic part of sending the HTTP cookie along with all of our requests. And then we have this initialize Apollo utility here that allows us to do server side hydration. If we wanted to do, the Apollo team wrote this. I did not write this. This is smarter stuff than I do. So, they have some up to date code on that if you want to have a look at it. Basically, all that does is it just does some hydration behaviors if you're on the server, not on the server. That's very unique to the Next.js environment. If everybody's tracking with that. So, from there, we're going to go ahead and head on into our App.js environment here. This is the default wrapper here. And we're going to do is utilize our, we're going to go ahead and add in our provider from the Apollo client. So, here's where we're starting to get into the parts where I have to actually be just pasting in pieces. So, what we're going to do is paste in here. And I'm going to paste this code in once it's final. I'm pasting it in from my other copy. I'm pasting it in here. I'll paste it over to you. And everybody gets a paste. So, we're going to paste in the Apollo client, which we need. And then we need the app props type. Oh, actually, we're importing that one. And that I think I need the client. Yeah. And the other bits are from our state management. So, we're going to not worry about that one just yet. I want to show you, we are getting tight on time. I want to show you at least the querying part. We'll have to see about the easy peasy bits. I will make sure that's included inside of the repo. But it may not get to the easy peasy bits today, depending on time. It may not get to the easy peasy bits today, depending on time. So, we'll have a quick look here. Basically, with that in place, what we need to do is initialize our client. And with our client initialized, we're going to go ahead and wrap the Apollo provider around our app. Most of you should be aware of wrapping components. This is not what I would qualify as advanced React. But there we go. Sometimes it's a bit funky looking with the TypeScript stuff, though. So, we have this basic thing. Oh, my goodness, I'm putting in relative imports above. That's not going to fly. Let's go ahead and just make that a little bit prettier. Okay. We're going to go ahead and take this, and I want to paste this over to you all over inside of the app.js file. Which is... I'll just use this. Here we go. And I'm going to do this from now on. I'm just going to put this inside of my paste history, git command all, git commit, and call it a safe commit. And we're just going to make that a one-liner. If I had everything fine. Oh, I know. I forgot one ampersand there. Let's try that. So, that'll be our sync utility from here on out. And looks like we've still got about three or four people strong here. So, appreciate you guys sticking around here. All right. So, we have that in place for our client. What we're going to do now is create a an ability to fetch our users from inside of the app, just to show how the Apollo Hooks stuff comes together. And we're going to do that by using a function called fetch. And we're going to use that to fetch our users from inside of the app, just to show how the Apollo Hooks stuff comes together as just a way to fetch users, basically. And then we're going to try to get the easy peasy stuff squeezed in the last little bit. So, where we're at, we've gotten our... Let me just do a recap here. We've gotten the Hazura project set up. We've gotten the user a generated type SDK from there using GraphQL Zeus into our project that we can always be updating with that one command. Pretty great. Straightforward. We've gotten the Apollo client set up to be able to work with our GraphQL endpoint so that we can use the SDK Apollo Hooks inside of our actual application for fetching content, which we're about to demonstrate. Inside of our React components. That's where we're at. Let's go ahead and run that now from a basic... We'll just do it from the index file here. So, what we want to do now is we're going to go ahead and bring open a... I'll do this here because otherwise I'm not going to see it. I'm going to go ahead and open up my index pages, and we're just going to have this here slide by slide for comparison. So, what we're going to do, we're going to remove this bit here, and we're just going to list out an UI and UI of our users. So, that is the documentation thing. So, we're going to go ahead and just go here.

20. Querying and Displaying User Data

Short description:

We import the generated library and use the Apollo hooks to query a list of users with filter inputs. We can specify the fields we want and turn on/off certain properties. The result is a powerful way to query content without writing multiple queries. The retrieved data can be displayed in the UI. The boilerplate code may take time to write, but it provides a solid foundation for future development. Introspection allows us to see all the filtering options in the GraphQL API. We can also create mutations, such as a login system, to manage user state. Although the code will be provided in the GitHub repository, a faster walkthrough will be given to cover the main concepts. This part will be completed within the remaining 30 minutes of the workshop.

And I think it's just all of this internal bits here. I can just... I got out real quick. I believe that is the bits. Yeah. All right. So, what we want to do here is I'm just going to drop in a UL. Maybe. I always sign up for these crazy long classes, and then I'm always like, oh, yeah, I'll be fine. By the end, I'm just like typing garbage. Okay. So, we can confirm that this bit works here. So, let's go ahead and bring in our library now to help us work with this. We're going to import from... Wow. Maybe I was doing better when I was standing up as opposed to... From our generated library here. So, we're going to go ahead and go up to our utils, and we're going to go inside of our generated repo, and we're going to go inside of Zeus, and we want the Apollo hooks. And so, what we want is we want to do the use typed query. And from here, we're going to go ahead and do an actual data query. I have to remember with the use typed query here, it might be totally... It might be the spread operator. It is unfortunately not... It is spread operator. Okay. So, we're going to just spread these values here. So, it's data and it's error and loading are possible values here. Use the typed query. And from here, we're going to go ahead and just grab a list of our user. And because we have filter inputs, here's where people get kind of upset about GraphQL's inputs. So, we're going to go ahead and just grab a list of our user. And because we have filter inputs, here's where people get kind of upset about GraphQL's Zeus. And it might be fair, but I think if once you learn it, you learn it. So, it's okay. Your query is actually an array with your filter inputs as the first object. So, here we could do things like where... And you'll see these type hintings coming up, right? Where it's like, so nice. I mean, you can just kind of just drill down on here and you can say a name, equals Jesse, for example. So, you get the type hintings, which is just super fantastic. I'm going to leave this blank because I just want everybody, but I still need to pass in the first object. And then what I do here is I'm going to go ahead and just drill down on the properties. And so, I want the name, which is the only one that I actually have available to me in this context. And so, I say true on the field. So, I'm getting these types of things. So, I'm getting these key values that are mapped to the actual fields of the query. And I'm saying the ones that I want. Now, I can do things like, you know, password, or I can do things like an email here and say false. And if I was in a credentialed environment, I would be able to access that. I can't access that. So, I'm not going to be able to get access to that here. Sorry, like this. So, I can leave this as false, and I wouldn't even be requesting that. But I could do something is like if I were to say, you know, is admin, then make this you're actually requesting this, and if not, false. Like, that becomes the real power here in this way of querying. Because instead of writing a whole bunch of queries, give me an admin type query, or give me a user type query, an authorized user, or a user query, I can pass in Boolean properties to turn on and off the fields I'm requesting for, instead of doing like string interpolation to say I want this piece of data from my server when I am this person. And that I really like that, because that's kind of mapping the ideal use case of a GraphQL was, which is a super simple syntax for querying this content and executing these resolvers, but without having to write a whole bunch of different string types. So, in this case, I don't have access to it, no how, for right now. So, I'm going to just pass it like this. So, I have this user type query, I have this GraphQL query here, and what we're going to do is just come down here to our UL that we had, and we're going to go a very cheater style here and say okay, data, and data.map, and then we're going to go ahead and grab in the user and the index, and we're just going to return the LIs where we have the key is equal to the index here, and we're just going to pass in the user.name. And it's complaining about mapping, because data.user.map. So, we're going to do is data.user. This is a potentially undefined. So, we have this context. Let's check to see if we got what we wanted. Wait for a second for it to query. And we have our users returning from the string. So, it's a fair amount of boilerplate, and it takes a lot of time to write it, but once you have it, you have it. And then you can use this shell, this wrapper, and again, I'm pushing this all up to the server so you'll have this, and you can actually just clone this repo and be ready to go. But like, once the boilerplates in place, like that's a really, really good way to do it. So, if we wanted to have something like to see all the options that Hazura's filtering queries have for me, that generated GraphQL API, I can do all of that sort of introspection here directly inside of my IDE. And that's like really, really cool, you know? You can do things like that. And then you can also do things like, you know, like, you can do things like, you know, that's like really, really cool, you know? You can do things like is like and pass in whatever filters and stuff. So, that's the that is the basics of the filtering. Now, let's go ahead and try to create a mutation. Let's go ahead and try to create a login system here that will allow us to be able to create a yeah, create a sense of user state. So, we're gonna try that in the what is that? I don't know. Is that 30 minutes left? It's roughly 30 minutes. 15 or 30. 30. So, I think we got time. So, I assuming that nobody minds, I'm going to go a little faster here with some of the pasting of the code over so that you have access to it. And I'll really roughly because it's essentially the same concepts, I'm really going to roughly say what the code's doing without as much walkthrough on it. And we'll see if we can actually get this piece kind of running in 30 minutes. So, I'm hoping that's okay. You're gonna get the rough GitHub stuff today. I'm gonna wrap it up for you as well with a bow on it. So, that's gonna be cleaned up hopefully tomorrow. And that'll be something that'll be also well documented. So, let's go ahead and try. Nobody's saying no to that idea.

21. Creating Store and Model for User State

Short description:

I'm going to create a store and a model to store user state. The model contains actions for user-related behaviors. The model also includes a sign up, login, and logout actions. The sign up action resets any login errors, performs a sign up mutation, and sets the user and auth behavior based on the response. The login action has similar behavior. The logout action sets the user to null and performs a simple fetch to delete the cookie and redirect to the main page. This is the model for state management in PipeScript land.

So, here we go. I'm gonna go ahead and start with getting a store created here, which is gonna be what I use to store all of my state of the user that I'm pulling in. And inside of that store, I'm gonna be needing to create and I'm gonna have to push this up here in just a couple of minutes. I'm gonna go ahead and create my model. So, I'm not gonna be explaining too much what the internals of EZPZ, but the basics are you create these models and then you can create these actions for the models and then you get the pieces. I'm gonna go ahead and actually close down this terminal. So, we have some space. Let me go ahead and just update this model bit for you real quick. So, I'm gonna, you know, I'll do this. I'm gonna paste it in for you fast. And then I may have to patch as we go along. But I'm going to patch it with the running bits. So, we have the store. We have the model. And we're gonna also have an index.ts. So, inside of models, we're gonna have to patch this one for sure because I have changed the data model since that one was useful. And I'm gonna paste this one over here in the index. I'm going to push this up just for the moment. And I need my index file now. So, let's have a look at the model here and see what's going on. What we've got here is a bunch of types here that we no longer need because of the way I'm working this. So, all of my imports are aligned, which is good. So, the store types, we have a maybe interface for our user. So, the user is this is the actual store for the user inside of the state management. So, we have a user. We have a auth state is logged in or is an error. And then we have an action that is gonna be setting the user as a successful response from the server. And a set is logged in, a signup, a login, and a logout behaviors. These are actions on my state. This is state management in PipeScript land. So, yeah, again, twice the amount of code, but hopefully right at once. Apollo, we actually don't end up using here. So, we can go ahead and remove this. I saw a Discord message or I heard a Discord message. Is that for me? It's not for me. So, I'm gonna ignore it. And we're gonna go ahead and keep racing down here. So, what we've got is the store definition itself, user, auth is logged in, and error. So, we have this is the interface. Sorry, the interface. And then the store itself is declaring what the actual store is. So, all the actions. The action here is a store.user equals payload. So, whatever I send into the set user, I'm setting that on the store user model. So, under set user, I'm setting it on the user. On the set login error, again, whatever error I'm getting back to payloads are getting assigned to states. This is not a state management class. Easy peasy. It's pretty well documented. So, have a go at it. Sign up, async behavior. That's what thunk is. So, don't worry about that wording. The sign up action, what it's doing is it is saying store set login error is false. So, resetting any errors. And then it is saying cons results await client.mutation. So, this client, we've defined this already. This is the Zeus client that is using the either server or non server version of our endpoint. It is doing a sign up mutation. And here's where I need to patch this, because I no longer am returning roles and users. So, I can skip that bit. We have then is the payload. Yeah, so, the payload is coming in, and then the name and the ID and the operation name. This is sorry, this is variable syntax for GraphQL Zeus. So, this dollar sign comes from the GraphQL Zeus library. And it is getting that from the variables object. The payload is what's being sent in as the payload on this sign up action. So, a name and an ID are getting sent on this payload when it's getting called. And that's being this query, which is the result of this sign up mutation. And that sign up mutation is then checking for errors. If there are errors, it's setting a login error to true. If there is a user in response, it is going to go ahead and set the auth behavior. So, I'm logged in true, and it's going to set the user as the result. So, let's sign up. Login, we have the same behavior. We have the essentially the same things. I'm going to go ahead and drop these two pieces from the model, because I'm not doing an avatar or roles in this particular model. Again, client mutation, login behavior, payloads, getting assigned values. And I give it an operation name in both of these cases. Again, something that GraphQL Zeus exposes, because I want to see that in my observability metrics, because I'm using cloud, and I can kind of know what's happening. Setting users, if everything's happy, everything's good. On logout, setting the user to null, sets the store set to logged out. And I'm doing a very simple fetch to my logout API path, which just deletes my cookie and pushes my path with the Next.js router to the main page, so that I kind of clear everything. All right. That is the model. Let's go ahead and patch that for you real quick. And then on the index, is everything happy? I didn't paste the index for myself yet. So, let me go ahead and grab that. But it should be fine, because there's nothing fancy in there.

22. Setting up Store Provider and Creating Login Form

Short description:

We set up the store provider inside the Apollo wrapper and create a login form using React and easy peasy. The form includes inputs for email and password, and a button to handle sign up. The handle sign up function triggers the login action, which persists the user and the cookie. The use store state hook is used to access the state from easy peasy.

But it should be fine, because there's nothing fancy in there. This is just simply exposing everything. Easy peasy has a create typed hooks library, which is able to basically just take all of these behaviors and gives us things like a use store action, use store dispatch, use store state hooks, which allows us to be accessing our store behaviors in a wonderful way. Okay. That is everything we need for that. All right. What we need to do now is go ahead and put our provider on our app path. So, more copying code. If this is like driving you all crazy watching this, just let me know. But I'm excited about how this works, because I find this to be a really, really cool way to build. And as soon as you have the boilerplate in place, and you're not copying and pasting it a bunch of places, it's actually really, really fun to build this way. So, that should be everything that I need. Let's go ahead and head back over to the app file, which product am I in? I'm in this one. We're going to go ahead and go to app. And I'm going to go ahead and paste in the libraries that I wanted. So, what I've got here is the store provider. And then I have the actual store index file. So, the store provider comes on the inside of the Apollo wrapper, which is going to be the store provider. I think I copied it. I copied it. I did. Good. All right. And then we can go ahead and close that off with the store provider. Anybody knows a shortcut for that behavior? That would be cool. All right. So, we got the everything set up. So, what we can do now is we're going to create a very simple login form on our React form. So, we're going to go to the index page here. Let's copy this. And now we'll do this right here. Okay. It's all good. I'm going to do this from here. So, we're going to go ahead and I have a login form actually created. So, I'm going to grab it from grab some pieces here. So, we're just going to kind of move a little quick. So, we're going to just start to break this down. So, this is not great. We're not going to be doing this in the way that you should. But okay. Fine. Whoops. Let's go ahead and put this inside here. Right? Come on. All right. So, what do we got going on? We got a React use state for email address and password. This is going to be our sign up form. Then we have the use store actions, which is our login behavior. So, what we need to do is just quickly import React. All right. And we have the email set password, yada, yada, yada. So, we're going to go ahead and make a form here at the behavior. So, login, what this is doing is this is literally just giving me the login action, which is a function coming back from actions.login. That's the login action on the actions object from using store actions. Okay? Everybody get clear on that? From the application, we're going to just put this just here inside of the we're just going to put a little block right here. This is where our form is going to live. And we're just going to put in two inputs. And that's going to be the name or the email of state. Type is text. We'll put the on change directly on there. So, let's have a look at our brilliant login form here. So, pretty. All right. Now, we need a button. So, we're just going to handle sign up in this case. Could we still get the behavior that we're looking for with just sign up and not handling login and logout? So, this would be able to execute something. So, that button that we're going to do is we're going to go ahead and say on click. We're going to handle sign up. All right. We'll take that logic up here to the top so we can kind of look at this a bit better. Let me send you over the easy peasy app client real quick. And so, on this sign up behavior, all we need to do is pass in the payload of the email and password. Which actually I think is just this. I don't even need a payload. So, it's just that object. And let me just make sure that I have that all set up correct. I'm always kind of paranoid on this stuff. So, I'm just going to I don't think that the button sends behavior. But I've heard that there's some discrepancies there between browsers when it's inside of a form component. So, I'm just going to do this for now. I would research that. That might be unneeded. So, handle sign up is going to do the login action. And that login action is going to persist my user. It's going to persist my it's going to persist my cookie as well. So, I will be logged in. And so, to replicate that behavior, we're going to grab the state from easy peasy. So, we're going to grab the use store state.

23. Debugging the Sign-up Form

Short description:

We're using conditional checks to hide the sign-up form if the user is not logged in. If the user is logged in, we show the user's name. We have default user values and a password for reference. We need to add the name field to the sign-up form. After signing up, we expect to be logged in, hide the form, and set everything up. We inspect the network connections and check the console for errors. We debug the sign-up mutation and check the payload. We verify that the form is correctly passing the name, email, and password. The sign-up process is getting to the expected point. We check the use store actions and confirm the correct behavior. We continue to debug and analyze the sign-up form logic.

So, we're going to grab the use store state. And I'm going to grab the user. And I just bumped something. Whatever. I'm going to do not just the user. I'm going to grab the current auth condition as well. Is logged in. And I'm going to do that as the state.auth.isloggedin. All right. So, we're using these conditions now. So, this is going to be my conditional check here at the top. If I'm so, we're going to just hide the sign up form. If I'm if I happen to be not logged in. And then if I am logged in, we're coming down to the wire on this sucker. If I am logged in, we are going to show user.name. I think that works. So, what we have here. We got the default users being passed in user dash one at fake.said. And we have the password of 123 in case we need to reference that later on. What that's going to happen is so, it's taking the default values of the form. When I hit sign up, which I want to make sure I use the right behavior, I used login. So, that would have already been making me a sad person. So, we're going to go ahead and go sign up here. So, sign up behavior is going to let me sign up these users. I need a name on there. So, what we can do here is what are you looking for? Looking for is not assignable type, email, password. Property name is missing. So, yeah, you need name. All right. Let's just toss that in there real quick. We've got name, set name, fakeyzed. Okay. So, we're going to grab that behavior down here. We're just going to pass in that value. You're not really needed, I guess, because we're going to be able to pass it in anyways. But, you know, make it all proper here. And we have the set name there. Let's check. Fakeyzed. Okay. Everything should be good. What we expect to have happen is when I run that sign up, I expect to get myself logged in. I expect to hide the form. And I expect to be able to then get everything set up. So, let's go ahead and test it. Let's go ahead and try. So, it's doing the behavior. We'll see in a second. I can inspect the network connections. So, maybe there was an issue. Let's go back and look at the console. No console errors. So, we're going to do what's the console complaining about? We're going to put this console on its own window here just so we can kind of debug real quick. So, we'll go to the network tab. We're going to try firing that again. And what do we get? So, the fetch behavior undefined. So, what we can do is check to see what's happening underneath that sign up mutation. Which is underneath model. So, sign up is getting this payload. We're just going to inspect that payload as it comes in here. And then the client mutation here of sign up. I think we need to get the name, email. So, let's go ahead and see if we're seeing the stuff we need to see. So, we'll try to sign up again. Do we see that payload even coming in here? So, it appears that maybe actually my form is busted because it's not even getting here. So, let's just have a quick look at the form here. So, back to the index page. Right. Index page. So, on that button click, let's just have a quick look here and see that we are, in fact, getting the name, email, password. So, we are getting that called. And it does actually appear that we're getting it inside the model as well. So, the path for sign up, I don't know why it's trying to call it. Maybe I sign up, sign up. Okay. So, it's working. It's getting there to the, to where we expect it to go. The use store actions, actions.signup. I'm not even talking to the microphone anymore. Okay. Actions.signup. So, let's go ahead and have a quick look here to see what's happening. Use store actions, use store. Yeah, yeah, yeah. Just check my other logic here on the sign up form. Make sure I didn't pull in something stupid on accident. Nope. That should be correct behavior. So, the, we want the index page. All right.

24. Debugging the Sign-up Mutation

Short description:

We're encountering an error while attempting the sign-up mutation. It seems that the sign-up mutation is calling localhost, resulting in a 400 error. We tried bypassing the issue and checked the monitoring tab but did not find any operations. We also attempted an incorrect sign-up to debug further. We're now exploring the use of a different mutation approach. We're passing the parameters directly and attempting a network call to sign up a user. The network call is successful, and the user is signed up with the expected cookie response. However, we still need to address the error in the original sign-up mutation. We suspect that there may be a bug related to the variable helper. We'll continue debugging to identify and resolve the issue.

We're going to go to the model here again real quick and just have a look at the model. So, sign up. This is firing. Okay. But here's where we're getting the issue. So, we can try this. Not there. We're going to just try this. Why is this complaining about We are just about out of time here. But I've got I got time to try and diagnophase this particular event so go ahead and totalize for the line of question that's up to you. So I didn't intend to do that but we're definitely getting an error on this attempt here to do the mutation. So it tells me that this sign up mutation here is well what we can have a quick look here. What's going on here? So the client, I wonder if I need to reboot this after I've done some work with the environment variables here. If any of you have any idea, feel free to hop on. We can debug this together now that we're right at the very hairy, hairy end here. Sign up is theoretically working just fine. Email. Well, I think I know what the issue is. I think I'm I'm. It needs to make sure you see a pass in the password payload, email, name and password. Fine. So it's calling local host, which is kind of the funky thing here. From the 400. Well, we can try here. This is a bit of a bit of a stretch. We're going to go ahead and have a quick look at the monitoring tab and see if we see the operations. No. So we got the sign up action here. Password, name, email, sign up input. We verified that we were able to do a sign up from the API. And we verified it. Let's try it this way. Let's just go ahead and do an incorrect. This is bypassing the easy peasy here. But if we go back to our index page. Make sure that I'm really pulling this guy in here. Create email, name, password. I feel like I'm exporting the wrong thing here. So what I'm going to do is for the last test here, if you all want to give me a quick sign of life in the chat there that you're actually still watching or engaged on this. If I'm talking to my people. There's a sorry, there's a chat that I didn't see. Sign up, thunk, error, cannot resolve, mutation, sign up, harams. You solved it already, Nathaniel? Cool. All right. So let me see. I'm going to try this. Let's try and bypass this. So we've got the we've got use type query here. Let's go ahead and bring in use type mutation. We're going to go straight to the source here. The reason why we can't use this over there is because it's a hook and it's inside of a functional call. So we got use type mutation here. And on that use type mutation, we're going to just do this down here. And just see if that works. So use type mutation, we're going to do. Use type mutation equals. No, putting that backwards here. So we'll call this sign up or move sign up. Data error called. And that's going to be use mutation, use type mutation. Yeah, one second. Yeah. Well, we're not going to worry about actually calling it for now. So what we wanted to do is a sign up mutation. Which gives us params of oh, I wonder. I wonder, I wonder, I wonder. All right. We're going to go and pass these params here just straight, not even going variable route. We're going to go name, email, password. So that's like what we'd expect here. And then we want the return object on that. ID true. And I got a little bug in my code there. So we're just going to, we're just going to attempt to call this just by itself, which in theory should give us a successful network call. And signing up that user. So we're going to try it here. I'm going to just give us a different user because I want to not have a problem with attempting it later. So if we try this, I'll make sure I have the network inspector still running here. So we run that. Let's check the GraphQL request. So it's sent. Now obviously it's not listening to the responses, but so that, I mean that's working. That's working the way we'd expect, you know, we're getting the cookie back in the response headers for the Hazura user token. So all of that is a correctly shaped mutation. So it tells me that the error, I'm going to go ahead and remove all that bit here now. Because it doesn't help me at all with the behaviors here. So I'm going to go ahead and have the same behavior. Now I want to check if I had a goofy bug. Am I pulling in the variable helper? I don't think I am. Underneath models.

25. Checking Client and Path

Short description:

Let's check what the client thinks it is and see if the payload is in the correct shape. There seems to be an issue with the path, which is causing an undefined request to the local host. We need to investigate further.

And I am, I am pulling it in. Okay. So let's check what client thinks that it is. Let's see what client thinks that it is here. When it, when it tries to do this the right way. So you go to console here. Of course, yeah, query. Well, now, what we can do is this because technically, technically that should all be just fine there. Because that payload is the shape that it needs to be. That's called, it's called a post request to local also which I don't, an undefined request to POCAL, to POCAL host, to local host. So the path, it's called a weird path. Maybe having to. Let's, let's, let's walk up the chain here.

26. Testing User Authentication and Permissions

Short description:

We bypass the code and refresh the page to test if the authenticated user can only see their own details. The client may not be giving us the correct URL. We drop the model bit for functioning code. We test querying user data and encounter a permission issue. We regenerate the GraphQL SDK and check the request header, which is not passing the cookie. We attempt to re-authenticate the user.

Okay, so we got the process.env, zero endpoint, which it's going to do that on the. So it's just going to just give me exactly what I'm expecting here. If I look at the.env here. Let's make sure I'm, zero endpoint, it should be exactly what I'm looking for. Right, so zero endpoint, oh, maybe. No. So it's giving me the chain operator, which is what I want. Now, what I can do here. I can bypass because on the, on the, on the GraphQL Zeus. It gives me a client of its own. Let me just pull off that note check real quick. That's still looking at this. It gives me its own client. So if I go to model here. And underneath Zeus. I'm going to pull in its own copy of client, which is a generated. And just go down to the client here. Or it's not clients, something else not. This is last a GQL is what I meant. Okay, so if I, if I come here and I just grab GQL. And I use GQL in place of that fancy client check for these for these thunks, because they're unauthenticated anyways, like every, every case. So this is the signup behavior so I can do this and. And that should work for me just fine. Because I want to do is do this here. So I'm just going to bypass the funky code that we're writing. And it's just refresh the page we can measure to, I'm going to go ahead and kind of interesting and wonder if somebody deleted my data. Oh, no, I know. That's funny. Okay, so, yeah. So funny enough. When we did the successful mutation and got the response because it's an HTTP cookie. I have fakies Eddie's cookie in my, my history here. And because he only has select permission for himself. He, I get him in response right now, even though I don't have them authenticated because I didn't go through my state management. So, yeah, big goofy. It is interesting to show that that part is working. So, so you can actually see that it that is coming back if I go here now to the application. And I have to see if I can actually see the yes I'm going to go and delete this cookie here. And I refresh the page and I'll be back to an unauthenticated user, making that query. And it's literally just passing, passing the HTTP cookie, if it exists. And if it's there is a that sees it, it gives it that that user. That's, there's no local state that I'm pulling from it's just passing that cookie along. When it's when it's allowed to. So, that's really cool that at least you got to see that part of it working. However, as even get the state here to actually work. So let's test this now. And see, because it's gonna be really interesting to see here. Was this the sign up. So this is the sign of mutation. Now so we got a successful sign of mutation. So, technically, so it worked. It worked. Just gonna turn it off right now. And, and so what you're seeing now is we have fake EZ in the account now because I'd already made the request. The theory here now is if I refresh this page, I'll only see fake EZ, because the next request to the Hazara server is going to be authenticated, and he'll only have access to see his own details. So, very fresh this page and see if that theory proves, which it doesn't. Might be because I'm actually fetching from cache here. Because of Apollo now. May have to give it enough time to clear the cache. But so what we have here is we have a fake EZ, and what we can potentially try here is to see based on this is the last thing we'll test here so there was an issue with the client here that I don't actually know at the moment but there was a problem here with the client that was not giving us back the correct URL. Probably. I want to say might be related to being a dot n call on client side and it's not and start local but I'd have to check into that, so I'm not actually sure. The fact is, this is the part that we wrote that sucked that part worked. So, I'm going to go ahead and drop the model bit in here so you have some functioning code here for you to play around with before I get around to fixing it. And then we're going to do one last test before we call it a wrap here. And that is to see if we are able to on the index page where we are querying our user data. I should be able to get the, the email. I am logged in. And not worry about it. If I'm not logged in. So, let's try that. And what I might be able to see. So, it's not letting me because I asked for data that I don't have access to. So, there's a permission issue that I've created where in my data layer, which is which is preventing me from querying that data and I need to fix the user. If I give it brute force behavior here, if I go to brute force approach, I would go to user and I go to permissions and on the select field. If I say row select permissions without any checks, able to select all columns. Theoretically, theoretically, I would be able to see that. Let's see if we get a successful query to the. So, I need to need to look into what the I need to figure out what the technical issue is there behind my permissions layer that I've clearly set something up goofy probably related to the JWT that's getting set. And just check that one more time, but I think that's probably I'm guessing that is the issue that I have, but that may be as far as I'm getting it on this one. So, the user has permission. Let's go ahead and just try real quick regenerating the GraphQL SDK. And the we can take a look at the actual request that was made. I'm going to go ahead and run this again here. So, the request is passing is it passing the actual cookie and that might be the thing to check your request header. So it's actually not passing the cookie which may not have gotten set them in response. In this case, and this is, this is something that there's some bugginess with with HTTP cookies, where if you've if you've attempted to actually delete the cookie, then it gets like, it gets like annoyed at you. So I'm going to delete this as in storage for easy peasy, so I can go ahead and attempt to re-auth the user. So the reason was the users not authed here. Okay, I'm going to go ahead and try.

27. Debugging Authentication and State Management

Short description:

So, you should still be fetching users because you're not actually requesting that field. Let's see if we can get that user to be authenticated again with a correct sign up. There seems to be a small issue with my state management as far as what's getting checked. We observed it working once, but I'm unsure why it's not setting the cookie anymore. I will be updating and fixing the code to make sure it's bulletproof. I will provide updates through email, Discord, and Twitter.

So is logged in. Fetch me the email, if not, return false. So, you should be still fetching users because you're not actually requesting that field. But you are. So something tells me that the, we should do it this way. So, root force approach, sometimes you got to try it. So, on that, on that email. If you're false. Don't try to request it. Oh, Okay, I'm going to probably stop goofing around here. Let's see if we can get that user to be authed again here with a correct sign up. Yes, as you pull it off right away. I'm going to try and get another user authed here. User three. Give it a second to process through. Can also just be working with some slow round trips here. This was the sign up and the response is setting the cookie, which also may not be happy with the fact that I'm sending it over. I'm sending it via HTTP. Response. So, user is created but why is it not setting now. So small issue with my state management as far as what's what's what's getting checked, but then if he's was that last request sent. Let's take a look. This is a request for the user, and where is the cookie sent. Yeah. Okay. It's. Let me try one last test here, where if I go into a different browser. Right haven't messed with cookie said I'm just, I'm a little bit grasping at straws here. Let's test it real fast. And then we then I'll have to call it a day. Give me a browser session. Whatever. So, here we go. Let's see what happens if we make a request to make sure I'm looking at the network status tab here. Make a request here with user five. And then the request goes out okay so you saw that work quickly and effectively. This is one of the issues with Chrome right now is if you're messing around with the browsers, and I'm not sure why that is the case. But that is. Let's set the cookie back let's see if it actually set the cookie. So, told me it should. Here's where it starts to get into a world that you've got to like be debugging like crazy for the NG rock might be causing an issue here that it's an HTTP port and on and on it goes. So, that may just be where we have to leave that one for right now. Just curious. Last little, last little test here how fast can I deploy this sucker to Russell. And then give it the right update the URL, so maybe close the bug gap. Okay. Okay. Okay. Okay. Okay. Index deploy. Okay. Okay. Okay. Since I added the good. I don't believe that they are going to work. You can visit the page though. Now the users. I guess is that request for that. Okay. Okay. Okay. Okay. Okay. You have the code. This, this pattern works. I've got it in a couple of production apps. And I need to figure out what like where it's coming off the rails here. I'm just seeing that we observed it working once. I'm just unsure why it's not sending the why it's not setting the cookie anymore. That's something I'll have to try and do a bit more debugging I will be updating the repo. So you'll have access to that. That is, unfortunately, but have a downer to leave it on the pattern of having that TypeScript connection to your server, and be able to use the hooks and being able to have the, the typings inside of the ID. That's where the magic set. So, pattern of authentication. It's nice when it works. I have to figure out where my bug is in my code. It is for sure somewhere dumb, like really dumb. I will be updating and fixing and patching and making sure that I get this bulletproof. I believe I will be having access to emails to notify as well as in the discord channel I will update when I have notice. So, find that out. I will be also publicizing this on Twitter. When the skeleton is done, which you can find me there. Yeah, so I mean, it works for the unauthenticated parts which is great. I have to say, because when all the cookies cookies are, you can set darker, and I, and it may be when we were when I was touching something in the cookie file today that that I bumped something that shouldn't have been bumped.

28. Final Thoughts on Workshop and Conclusion

Short description:

So, find that out. It works for the unauthenticated parts which is great. I bumped something in the cookie file today. That's a network request on that cookie, what was the max age? Thanks for watching and joining. I hope they were able to get some value out of that. GraphQL and cookies can make us. Have a good one. See you around at other conferences.

So, find that out. I will be also publicizing this on Twitter. When the skeleton is done, which you can find me there. Yeah, so I mean, it works for the unauthenticated parts which is great. I have to say, because when all the cookies cookies are, you can set darker, and I, and it may be when we were when I was touching something in the cookie file today that that I bumped something that shouldn't have been bumped. This is also partially why you don't put TS no check on things, so you catch catch issues.

No, I know I do know that I did change this piece. I wonder, I'm just curious. That's a network request on that cookie what was the max age, the max age should be plenty. I don't know. I don't know. That's it. It's like after you. So, thanks for watching. Thanks for joining. I hope that they were able to get some value out of that, and GraphQL and cookies can make us. Indeed, indeed. All right, have a good one. Thanks for watching and yeah I'll see you around at the other conferences.

Watch more workshops on topic

GraphQL Galaxy 2021GraphQL Galaxy 2021
140 min
Build with SvelteKit and GraphQL
Top Content
Featured WorkshopFree
Have you ever thought about building something that doesn't require a lot of boilerplate with a tiny bundle size? In this workshop, Scott Spence will go from hello world to covering routing and using endpoints in SvelteKit. You'll set up a backend GraphQL API then use GraphQL queries with SvelteKit to display the GraphQL API data. You'll build a fast secure project that uses SvelteKit's features, then deploy it as a fully static site. This course is for the Svelte curious who haven't had extensive experience with SvelteKit and want a deeper understanding of how to use it in practical applications.

Table of contents:
- Kick-off and Svelte introduction
- Initialise frontend project
- Tour of the SvelteKit skeleton project
- Configure backend project
- Query Data with GraphQL
- Fetching data to the frontend with GraphQL
- Styling
- Svelte directives
- Routing in SvelteKit
- Endpoints in SvelteKit
- Deploying to Netlify
- Navigation
- Mutations in GraphCMS
- Sending GraphQL Mutations via SvelteKit
- Q&A
JSNation 2023JSNation 2023
174 min
Developing Dynamic Blogs with SvelteKit & Storyblok: A Hands-on Workshop
Featured WorkshopFree
This SvelteKit workshop explores the integration of 3rd party services, such as Storyblok, in a SvelteKit project. Participants will learn how to create a SvelteKit project, leverage Svelte components, and connect to external APIs. The workshop covers important concepts including SSR, CSR, static site generation, and deploying the application using adapters. By the end of the workshop, attendees will have a solid understanding of building SvelteKit applications with API integrations and be prepared for deployment.
React Advanced Conference 2022React Advanced Conference 2022
95 min
End-To-End Type Safety with React, GraphQL & Prisma
Featured WorkshopFree
In this workshop, you will get a first-hand look at what end-to-end type safety is and why it is important. To accomplish this, you’ll be building a GraphQL API using modern, relevant tools which will be consumed by a React client.
Prerequisites: - Node.js installed on your machine (12.2.X / 14.X)- It is recommended (but not required) to use VS Code for the practical tasks- An IDE installed (VSCode recommended)- (Good to have)*A basic understanding of Node.js, React, and TypeScript
GraphQL Galaxy 2022GraphQL Galaxy 2022
112 min
GraphQL for React Developers
Featured Workshop
There are many advantages to using GraphQL as a datasource for frontend development, compared to REST APIs. We developers in example need to write a lot of imperative code to retrieve data to display in our applications and handle state. With GraphQL you cannot only decrease the amount of code needed around data fetching and state-management you'll also get increased flexibility, better performance and most of all an improved developer experience. In this workshop you'll learn how GraphQL can improve your work as a frontend developer and how to handle GraphQL in your frontend React application.
React Summit 2022React Summit 2022
173 min
Build a Headless WordPress App with Next.js and WPGraphQL
Top Content
In this workshop, you’ll learn how to build a Next.js app that uses Apollo Client to fetch data from a headless WordPress backend and use it to render the pages of your app. You’ll learn when you should consider a headless WordPress architecture, how to turn a WordPress backend into a GraphQL server, how to compose queries using the GraphiQL IDE, how to colocate GraphQL fragments with your components, and more.
GraphQL Galaxy 2020GraphQL Galaxy 2020
106 min
Relational Database Modeling for GraphQL
Top Content
In this workshop we'll dig deeper into data modeling. We'll start with a discussion about various database types and how they map to GraphQL. Once that groundwork is laid out, the focus will shift to specific types of databases and how to build data models that work best for GraphQL within various scenarios.
Table of contentsPart 1 - Hour 1      a. Relational Database Data Modeling      b. Comparing Relational and NoSQL Databases      c. GraphQL with the Database in mindPart 2 - Hour 2      a. Designing Relational Data Models      b. Relationship, Building MultijoinsTables      c. GraphQL & Relational Data Modeling Query Complexities
Prerequisites      a. Data modeling tool. The trainer will be using dbdiagram      b. Postgres, albeit no need to install this locally, as I'll be using a Postgres Dicker image, from Docker Hub for all examples      c. Hasura

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

GraphQL Galaxy 2021GraphQL Galaxy 2021
32 min
From GraphQL Zero to GraphQL Hero with RedwoodJS
Top Content
We all love GraphQL, but it can be daunting to get a server up and running and keep your code organized, maintainable, and testable over the long term. No more! Come watch as I go from an empty directory to a fully fledged GraphQL API in minutes flat. Plus, see how easy it is to use and create directives to clean up your code even more. You're gonna love GraphQL even more once you make things Redwood Easy!
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
Remix is a web framework that gives you the simple mental model of a Multi-Page App (MPA) but the power and capabilities of a Single-Page App (SPA). One of the big challenges of SPAs is network management resulting in a great deal of indirection and buggy code. This is especially noticeable in application state which Remix completely eliminates, but it's also an issue in individual components that communicate with a single-purpose backend endpoint (like a combobox search for example).
In this talk, Kent will demonstrate how Remix enables you to build complex UI components that are connected to a backend in the simplest and most powerful way you've ever seen. Leaving you time to chill with your family or whatever else you do for fun.
Vue.js London Live 2021Vue.js London Live 2021
24 min
Local State and Server Cache: Finding a Balance
Top Content
How many times did you implement the same flow in your application: check, if data is already fetched from the server, if yes - render the data, if not - fetch this data and then render it? I think I've done it more than ten times myself and I've seen the question about this flow more than fifty times. Unfortunately, our go-to state management library, Vuex, doesn't provide any solution for this.For GraphQL-based application, there was an alternative to use Apollo client that provided tools for working with the cache. But what if you use REST? Luckily, now we have a Vue alternative to a react-query library that provides a nice solution for working with server cache. In this talk, I will explain the distinction between local application state and local server cache and do some live coding to show how to work with the latter.
React Summit Remote Edition 2021React Summit Remote Edition 2021
43 min
RedwoodJS: The Full-Stack React App Framework of Your Dreams
Top Content
Tired of rebuilding your React-based web framework from scratch for every new project? You're in luck! RedwoodJS is a full-stack web application framework (think Rails but for JS/TS devs) based on React, Apollo GraphQL, and Prisma 2. We do the heavy integration work so you don't have to. We also beautifully integrate Jest and Storybook, and offer built-in solutions for declarative data fetching, authentication, pre-rendering, logging, a11y, and tons more. Deploy to Netlify, Vercel, or go oldschool on AWS or bare metal. In this talk you'll learn about the RedwoodJS architecture, see core features in action, and walk away with a sense of wonder and awe in your heart.