Welcome to Fauna! This workshop helps GraphQL developers build performant applications with Fauna that scale to any size userbase. You start with the basics, using only the GraphQL playground in the Fauna dashboard, then build a complete full-stack application with Next.js, adding functionality as you go along.
In the first section, Getting started with Fauna, you learn how Fauna automatically creates queries, mutations, and other resources based on your GraphQL schema. You learn how to accomplish common tasks with GraphQL, how to use the Fauna Query Language (FQL) to perform more advanced tasks.
In the second section, Building with Fauna, you learn how Fauna automatically creates queries, mutations, and other resources based on your GraphQL schema. You learn how to accomplish common tasks with GraphQL, how to use the Fauna Query Language (FQL) to perform more advanced tasks.
Building a GraphQL-native serverless backend with Fauna
Welcome to Fauna! This workshop helps GraphQL developers build performant applications with Fauna that scale to any size userbase. You start with the basics, using only the GraphQL playground in the Fauna dashboard, then build a complete full-stack application with Next.js, adding functionality as you go along.
AI Generated Video Summary
Today's workshop focused on serverless development with Fauna. The workshop covered topics such as building a client-serverless model, exploring data access patterns, and creating a serverless application. It also delved into user authentication, session management, and querying data in the front end. The workshop highlighted the power of Fauna for data manipulation and the flexibility it offers for building applications with fine-grained access control.
1. Introduction to Serverless
Thank you for joining us. Today, we'll be discussing serverless and its benefits. Serverless eliminates infrastructure concerns, automatically scales, ensures high availability and security, and offers value-based pricing. With serverless, you can achieve zero downtime and satisfy compliance requirements. Fauna, a serverless database, provides strong transactions, fast performance, and works well with next-generation serverless providers. It's a great fit for front-end developers and offers a smart API layer for easy integration. Let's dive into the workshop and learn more about serverless!
Thank you for joining us. And now let's get started. Thanks for joining us today. We've been waiting to get started. My name's Rob. I'm one of the people who's gonna be walking you through the workshop today. I want to make sure that you're all in the Discord server with us. I'm going to go ahead and drop the link to the slides that I'll use in there now, and we'll also give you a link to the workshop later. so that you can go back and do this, either yourself, review it yourself or take it to your teams to do it so that you can run through it on your own. It is publicly available, but the differences will be here today to answer your questions as we go and to walk through it with you.
So without any further ado here, I'm just going to dive right into the workshop. So I'm going to go ahead and turn it over to Rob to give you a little bit of a tour of the discovery space. And then should give you some resources, and then Shadid is going to take you through the workshop.
So when we talk about serverless, we talk about four key things. These are typically the same for all your different serverless providers. There. First, there's no infrastructure concerns, so you don't need to provision clusters, servers, patch operating systems, all of that stuff. You don't need to worry about that. The provider takes care of it for you. And access is just provided via an API or or as a service. Second, it automatically scales, so you don't need to think about provisioning. If you have zero users, it should scale down to zero and you shouldn't be paying for any of that compute. If you have a burst of traffic, it should scale up immediately. And you shouldn't have to worry about any of that. And that's what Fonda gives you for your database, similar to what function as a service providers give you for your compute. Third, it should be highly available and secure. And so these aren't things that you should have to worry about. Right. If there's an outage somewhere, the provider should be taking care of keeping you up and giving you access to your data. And that's what we do at Fonda. And then finally, it should be paid for value. If you have no access to your database, you shouldn't pay for access during that period. If you store, you know, 10 gigs, then that should be 10 times as expensive as storing one gig. Right. And, of course, there's a free tier that we give you to help you with that. But the principle there is you pay only for the actual access. You don't pay for hours of running Fonda or anything like that. If you have a lot of access and those reads and writes go up, if you have zero, it scales back down. And that scale to zero concept is really important in serverless. Some of the benefits real quick of using a serverless back in like Fonda, you should really be able to achieve zero downtime, at least in terms of your your database. And this helps you like yesterday, there was this big outage that everybody knows about. If you were architected on a single region and it happened to be that one that went down, then off you go. Right. There's no way to avoid that. But Fonda has spread across and above these regions in a way that all of our traffic failed over to the other regions without your application having to do anything. So as far as I know, we didn't have any reported outages yesterday, even though we were dependent on one of the on the region that went down and we have zero reported cases of data loss. So this is a really big advantage for you as a front end developer who just wants to store and get your data back. So all these things that you don't have to think about. So this can also help you satisfy compliance requirements. This is with like region groups that we offer, and we're not going to go into this today because the point of today is to build. It can help you reduce latency with phone number because your users are accessing the closest endpoint. We'll get to that later. And it's a minimal increase in spending to have all that redundancy. You're not running two copies of your database, right? You're running your traffic spread, which is the same total cost as opposed to doubling the cost or tripling the cost to have it in multiple locations. We also do this without the problem that you see on the side of eventual consistency, because Fauna has strong transactions. So instead of getting in a case where you have to check and make sure that you have the most recent data or use locks or anything like that, you just write to a single endpoint and your users read from the endpoint closest to them because everything is a strong transaction. You're just always going to have the most recent data there. Other serverless databases don't give you this guarantee. I mentioned earlier, it's also fast. Right. These are the actual performance numbers. You can confirm these for yourself by going to status.fauna.com. You're looking at single digit, millisecond reads and double digit, millisecond, strong, strongly consistent transactional writes. So it's really performant for your applications, which is important when you're creating front end experiences. Right. Fauna works with next generation serverless providers very well. We're not going to get into deployment today, but if you're already running your app on something like CloudFlare pages or on Purcell, it's a great fit and we have lots of material to help you integrate with that. And again, this is forms sort of a smart API later over Fauna. The GraphQL service does the same thing for you. So you don't need to worry about where to route your traffic.
2. Building a Client-Serverless Model with UDFs
You'll learn how to build a client-serverless model using user-defined functions (UDFs) and protect access to your data. By the end of the workshop, you'll have a production-ready model for authenticating users and extending GraphQL queries. We'll guide you from knowing nothing about Fauna to setting up a ready-to-use system in just a few hours. UDFs help you separate business logic from front-end code, making queries and mutations simpler. We'll also cover the principle of least privilege, generating temporary tokens for user login, and authorizing access to resources. The workshop focuses on UDFs and secure data access.
You just hit graphql.db.fauna.com, as you'll see in the workshop today. And we take care of that routing for you. And what you're going to build today is a model that we call client serverless, where you don't have all this other infrastructure in between. You just have your front end and communicating directly with Fauna. And that's the thing that you manage. And that's the thing that you concern yourself with.
This workshop is derived from something we call the Zen of Fauna. You're not going to cover all of this today. The workshop mainly covers the first two. Always using user defined functions, which are implementations of your resolvers in your GraphQL schema. We'll talk about why. And there's a security piece that we're going to teach you about how to only put the keys in your client that can log in and nothing else. Right. So this is how to protect access to your data.
So when you're done with the workshop today, you're going to have a production ready model for authenticating users and for extending your GraphQL queries. This workshop builds up pretty smoothly. What was the goal where we try to only introduce one thing at a time that's new for you. But we still take you from knowing nothing about Fonna to having this production ready setup that you can use in the next over the next three hours. So we talk about user defined functions being everywhere. And the reason that we do this is because it lets you take the business logic out of your front end code and store it somewhere else. Right. For basic queries and mutations and graph QL, that's already going to be provided for you by Fonna. When you create a type, we give you a find type by ID, update type, read type, delete type. I'm sorry, create type, delete type. But for more complex cases like we'll cover in the workshop, you're going to encapsulate that logic in a UDF. You can test it, but it also makes your your queries and your mutations simpler. And then, of course, we talked about this piece of least privilege, the principle of least privilege, here with the login keys. Were going to show you how to generate temporary tokens for users when they log in and how those tokens are used to authorize access to resources in your database. I want to go back real quick. The other important thing to note there is every other permission is denied. In the workshop, you can register a user, you can login a user, but you can't do anything else. Because you have to ship these keys out with your clients, right? There's no way to get it out into your users browser without exposing it. You want to make sure once it's exposed that it can't do anything else. We're going to show you how to do that in this workshop.
3. Contact Information and Workshop Introduction
Before we go, I want you to have our contact information. We have our own Discord for you to get your questions answered. We also have Fauna Labs, a collection of tools and code to help you build with Fauna. Follow Fauna on Twitter or ask us questions via email. Access the workshop slides in the Discord channel. Visit fauna.link.gqlworkshop to join the workshop. Shadeed will guide you through it. Thanks for joining us!
I don't know why that slide is in there. Before we go, I want you to have our contact information. I'm going to hand this over to Shadeed next. I will put this information in the Discord as well. We do have our own Discord, don't join it until after the workshop. We're not trying to take you away from GraphQL Galaxy, but as you build with Fauna, it is the place for you to go get your questions answered. We also have Fauna Labs, which is a collection of tools, sample applications, repositories, a lot of code for you to help build, to help you build with Fauna. And then you can always follow Fauna on Twitter or ask us questions on Twitter or via email and our information's in the slides here. Again, these slides are already shared in the workshop channel, in Discord, so you should have a link to them already. I'm going to go in there and add this information individually as well. And I'm also going to add a link to the workshop, which you can access by visiting fauna.link.gqlworkshop and at this point I'm going to turn it over to Shadeed to take you through that workshop and get you started. So thanks for joining us, everybody. Welcome everybody.
4. Building a Serverless Application with Fauna
Today we're building a production-ready serverless application with Fauna. You'll need a basic understanding of GraphQL and a Fauna account. Create a database, select a region group, and import a schema to get started. Fauna is a database that provides a native GraphQL API. We'll explore resolvers, user-defined functions, and the Fauna query language. In under five minutes, you'll have a GraphQL backend.
So today we're building with Fauna. We're going to be building a production ready serverless application. All right, so let me just share my screen. Let me know if you can see it. Can you see the screen? Cool. I see it. All right, so let's get started. So you can access this, the whole workshop, after we're done, and you can do it by yourself. We're going to keep this updated, this whole workshop guide. So let's get started.
So, the first thing that you're going to need is, you have to have a little understanding of how GraphQL works. The other thing you need, other prerequisite is to have a Fona account. So if you haven't already, just go ahead and create one. So, I am going to go to dashboard.fona.com and here I'm already logged in. You can create a new account, if you haven't done it already. You can sign up a new account for free. You don't really need your credit card or anything like that.
All right, so the first step is to create a database. So let's go ahead and create a database. And here I'm going to call my database Shade Workshop, GQL Workshop. All right. And I'm going to select a region group. So for this one, I'm gonna select classic. You can learn more about the region groups and what they stand for in Fona documentation site. So, for now, I'm just going to go ahead and select classic and create our database. Okay, so let me go back to this workshop page and we're pretty much going to be following this. So, Chapter 1, prerequisite sign up for a Fona account. And if you're absolutely new to GraphQL, I'll visit introduction to GraphQL just to learn a little bit about GraphQL. So, you do need some basic understanding of GraphQL to follow along this workshop. All right, so, all right.
So, first, we created our database. Now, let's go ahead and create a schema and I'll show you how easy it is to get started with Fona. All right, so, here I am in my terminal. Let's open it up. Do touch. All right, so here, let's just bring it up here. All right. So I have a simple schema. So I'll just copy this. So schema for a store. So you have a name of a store, email, payment methods, which is an array of stream and categories. So all you do is you just, so again this is a very basic schema with just one model which this model is going to become. Become a collection, just a table pretty much. So all we do is just save this and you go back here and we go to GraphQL and our Fontain dashboard. Here all I have to do is import this schema. So I can go to desktop, workshop, schema. There you have it. Fontain detected everything from that simple schema and created a bunch of stuff for us. It created the queries, the mutations, it also created the tables. For example, if I go over here in the collection, you'll see that I have a store collection now. And it also created the queries and the mutation by default. So I can find the store by ID and here from the playground, I can actually run those queries And find a store by ID, I can create a store, an update a store, delete a store. Let's go ahead and do that. So I'm just going to create a new store. All right, go ahead and create a new store. And there you have it. And now if I go back to collection. See that that new store has been created. Now one of the important things to remember here is Fauna is not an application server. So it's not something like Apsync or Hasura. Fauna is a database first. It's a database that natively gives you GraphQL API. So you can use the GraphQL API to natively talk to the database. Later in the workshop, we're going to look into how resolvers work in Fauna. So if you have some basic understanding of GraphQL, you know that every business logic is pretty much a resolver in every GraphQL operation. So we're going to take a look into how resolvers work in Fauna and how user defined functions work. And we're also going to dive into FQL, which is Fauna query language, which is the proprietary language to interact with Fauna to write some of the more advanced things in Fauna. So let me go back to the workshop page. So under five minutes, we pretty much created a GraphQL backend. So there you have it.
5. Exploring Data Access Patterns
You can call the backend to perform various operations from your client applications. Let's do a query to find a store by ID. If you have any questions, feel free to ask. In the next section, we'll explore data access patterns in Fonna.
So right now you can you can pretty much call this backend, like to call, you know, create store, update store, delete store, find the store by ID, You pretty much do all these operations from your client applications at this point. That's pretty cool.
Okay, let's do a query. So here, find the store by ID, So I'm just going to use this ID. So if you guys have any questions, please feel free to ask in the Discord or in the chat.
All right, so let's move to the next part. So in this section, we already learned about how you can upload a schema, how Fonna generates queries and mutations, so let's move to the next part. All right, so let's see the data access patterns in Fonna and how they actually work.
6. Building an E-commerce Application
In this workshop, we're building a simple e-commerce application similar to Shopify. The data model consists of owners who can have multiple stores. The GraphQL schema includes the owner's name and unique email, and the owners have many stores. We can auto-generate queries and mutations, and later create our own. Let's move on to the next part of the workshop.
Okay, so first of all, this is the type of application we're trying to build in this workshop. It's going to be a really simple application. Well, it's a really simple application. It's kinda like a e-commerce sort of similar to Shopify. So the data model we're gonna use, it's gonna be similar to Shopify where you have owner of a store. So in Shopify, you can just sign up, you can create a store, and Shopify is this SaaS vendor that has multiple stores. So it's a data model is going to have an owner and an owner can have multiple stores. So as you can see, this is going to be our pretty much our data schema, data model. So you have an owner, an owners, manages, main stores.
Alright, so let's take a look at the GraphQL schema again. So again, we are introducing a model and owner has name, email, which is going to be unique because we want to have unique emails for each person signing up in the application. And then owners has many stores and this is defined through our relation. And just because we have this store inside an array Fauna knows that this is going to be a has many relationship. It's going to just copy that. Let's just go back over here. Go back to our playground in Fauna. And here what I'm going to do, I'm going to replace the schema. Let's go ahead, replace this. It's been updated successful. And now, what I can do here is, okay, I can open up the queries and we can see that the new mutation, the owner update owner, find owner by ID. New queries and mutations are already generated. So following gives you the ability to, so following gives you the ability to not only auto-generate these queries and mutations, but it also gives you the ability to create your own. So, and that's what we're going to take a look at later, like how you can create your own queries and mutations and things like that. through create your own resolvers and to UDF and other stuff. So let's just go ahead and just go back to our workshop slides. Let's see. So it gives you a little bit more information about like how you can updates your schema. So this is what we just...
7. Indexes and Data Access Patterns
Let's take a look at indexes, which are the data access pattern of accessing data from a Fauna collection. We can get owner and all the stores belong to the owner by this index. We can also get a unique owner by their email. You can create more indexes without re-uploading your schema. Just select 'new index' from the dashboard.
All right, okay. So now let's take a look at the indexes, okay? So let's take a look at indexes. So here, so indexes are the pattern like the data access pattern of accessing data from a Fauna collection. So for example, our schema auto-generated. So if you look at our schema again, our schema auto-generated to indexes. So now we can get owner and all the stores belong to the owner by this index. And we can also get a unique owner by their email. Just because we defined this unique keyword. So now those two indexes has been created. Now you can create more index. So let's say, if you have something like, I don't know, maybe home address, something like that. And you just, or postal code, and you wanna find the user by postal code, you can create an index. And you can create an index without re-uploading your schema. You can create, let's say your schemas already have that key, you can create an index directly from the dashboard. Let's just put there new index, that's just an option.
8. Creating Owners and Custom Queries
Let's create a new owner and associate a store with it. We can find the owner by ID or by email. To find the owner by email, we define a custom query in our schema and Fonna automatically generates the index for it. We can also define an index with a different name using the index directive.
Alright. Okay. Alright, so let's create a new owner. Let's copy this, go back to our GraphQL playground. I want to owner, alright, so mutation. I'm gonna be owner, pass the true index. Okay, so now we're gonna create a store and have this store associated with the owner we just created. Okay, so let's do that. So here, you can see create store. We gave a name, email payment method categories. Now, here in the owner field, you can say connects and this is your foreign join pretty much in your table. So if you're coming from like a SQL backgrounds, MySQL, you have foreign key constraints. So pretty much this is the relationship. This is where the connect is where the relationship happens. So let's take this ID and it's connected through here. And there you have it. Store has been created with and it is, so it got associated with this owner. We can see, we could have just a button that you the owner information here as well. Let's create another app, so I, this one and this time it's also for the users here to see the owner information is also getting back here. All right, awesome. All right, so here we're just showing you how you can find the owner by ID. Pretty much this similar, it's pretty much this query where you just pass in the owner ID. So here it just, this ID is actually going to add to that as well. This ID. And there you have it. So all right, awesome. Finding owner by email, we sort of already talked about that. Okay, so alright, so now let's go ahead and create another query. And this time we're going to create a custom query, and we're going to find owner by their email address. Okay, so to do so, we're going to have a query defined in our schema. So let's go back to our schema. We'll create a query. I have a query, we're going to call this query find owner by email. It's going to take in a email string, and it's going to return a number object. Okay, so let's save that, we have to upload it. So let's go ahead and let's list this again. And, Here, now, we see that a new query, find owner by email, has been generated. Okay, now let's dissect this a little bit. If I go back to my indexes, I'll see that there's a new index that has been created, and it's the same name as this query. Okay and this is going to target that email field. So whenever we run this query, we can now find owner by their email and Fonna just auto generates that for you under the hood. So all we had to do, just define it in our query, and it's been taken care of. All right, so let's go ahead and bring up a tab here, so I'm just gonna close some of these. Just have a query down there. Got it. All right, okay, so you can also define an index with index directory. So let's say I don't really wanna name that, I don't really wanna have the name of that key find owner by email. Let's say I wanna name it by email or something like that. So you can just use the index directive and do it that way as well. So that's just an option so that way, indexes will be a different name. So that's that.
9. Getting Owners and Stores, and Custom Resolvers
Let's take a look at how we can get all owners and stores in Fauna. We define a new query called 'list owners' that returns an owner array. We can also get the stores by creating a new rule. Now let's move on to creating custom resolvers in Fauna. We want fine-grained control over our data and data access patterns. Fauna is a database that natively supports GraphQL, making it easy to integrate with any source of application. Next, we'll dive deep into creating our own resolvers using user-defined functions.
Okay, so now let's take a look at how we can get all owners. So let's go back to the Raft tool, okay? So here we see we have different types of queries, but what if we want to get the list of all the owners, or get a list of all the stores? And stores in a certain table or in certain collection. So how do we do that? All right, so let's go ahead and let's go ahead and see how we can do that. So the first step is we define a new query. And here, the query is called list owners, and it is returning a owner array. Okay, so let's go ahead, that end. All right, again, by now you guys are familiar with the rule. So we save the schema and replace it. All right, so you can see the list owner just popped up. Just remove it. It's supposed to have data, email. It's missing there. We can also get the stores. I'll just create a new rule, and we'll just pass it here, and the information item that talks to the image. There's data, OK, so it's trying to get all the owners. Here we get all the owners. Well, we only have one, so maybe we should create another one. We're adding delegation. Return the ID, let's return the end of email. $new $email. changing to $original. All right, email once. Okay. Tree of fire then email stores. That's not a tree of fire. Maybe, let's do the name. $neel more now it's the stone isn't Mom. It was too. So we have one here that has a store another one on the concentrated and that does not have a store. Alright. Well, all right. So to hear. It's the same thing. Just demonstrate it. So pretty simple free All right. So next let's take a look at how to create a custom resolvers. Okay. So before we go into custom, so so far what we did we just made changes to our schema and fauna and auto-generated this indexes auto-generated the data access patterns. So based on our schemas so far. All we did is do everything in our schema and and yet that's that that's that's great. But we still want to have um better control over our data better control over our data access patterns. Right? So Yeah, so what we want to do is create custom resolvers to have fine-grained control over how we query data. And next we're going to take a look at that. So let's let's go back and review everything we did first. So so far, we learned how, you know, how we can create a schema and you kind of learned about how the Fauna Dashboard sort of works. We also learned that there is a GraphQL playground inside Fauna and we learned about Fauna being a database and not an application server a database that natively supports GraphQL so you can pretty much hook up Fauna with any source of application. So that's one of the big benefits that we have. So if you have a Java application and you know, there's no Java driver or anything you can just use GraphQL and interact with your with your back-end. Let's say you building a mobile application with Flutter or something, you can just just hit that GraphQL API and a lot of the time you're just building application with simple CRUD and Fauna can just do that simply by creating schemas and uploading. In Fauna, you just upload the schema and it will create those data access patterns and it's as easy as that. So, all right. So next we're going to go to take a look at custom resolvers. All right. So, this is when we're going to dive deep into the broader functionality of Fauna and how you can create your own resolvers. And the key to create resolvers in Fauna is to use user-defined function, or QDS. Okay? All right. So, if you're not familiar with GraphQL, then... So, just a quick intro to what the resolvers are. So, basically, whenever you're creating a GraphQL service, a GraphQL server in Node and in Java, or whatever language you want to do it in, there is a data layer and there is an application layer. And in the application layer, you define your resolvers. And resolvers are just functions, methods. So, basically, in your resolvers, you will have some of your business logic and how you access the data, the data access pattern logic. Now, in Fauna, we can define these resolvers in the data layer itself. Now, you can use Fauna with other GraphQL services as well. For example, you can create an Apollo server and you can have Fauna just as your data layer and not use the GraphQL. And you can just query Fauna from your Apollo server or you can use GraphQL and then return your response back in GraphQL. So, there is a lot of flexibility what you can do with Fauna. All right, so let's dive into the custom resolvers. So here, it kind of explains and again, we're going to make this link public and you can kind of see the things that I talked about. So, basically how, what the GraphQL resolver layer is in GraphQL and how business logic is handled in the resolver.
10. Creating a User-Defined Function and Resolver
So it's kind of described here in more detail. If you want to go ahead, then you can take a look at it as well.
All right, so let's create our first user-defined function. Okay so... All right, so we're going to start with something really simple. So we're going to create a resolver that counts how many stores we have in our store collection.
Okay, so by default, that is not generated. So we need to create a custom resolver to create that. So let's go ahead and do that. So first, what we do... We go into functions here. We click on New Function. So we name it, getStoreCount. And this is the code that we have to write in the function body. So let me go over it real quick.
11. Power of Fauna for Data Manipulation
Fauna allows you to write complicated application logic or complicated data access logic in your database layer. You can create user defined functions to handle complex relationships and perform advanced queries. This gives you the flexibility to retrieve specific data sets based on various conditions. You can also use a separate application layer to interact with Fauna without modifying the database. This makes it easy to integrate with front-end client applications and eliminates the need to move your data. Fauna is highly versatile and empowers you to manipulate data and write data-driven business logic in your database layer.
Okay. It's still returning. Let's do this. Yeah. So, counting all the stores. And the store collection. Alright, so that's how we create a custom resolver. And now, you can see that. Now, you can kind of understand the power behind it, right? Fauna allows you to write complicated application logic or complicated data access logic in your database layer. You can create, like, with user defined functions, you can have a really complicated relationship. So let's say you want to select, let's say if you have a large scale application and you have a store that are categorized as music stores, and you want to get all the music store that has a certain type of vintage record selling, and they're all on sale. So you can combine all that logic and package it in a user defined function and then just have it as a query or a mutation, and you can just get that complicated data. And you can do that calculation in your data layer. So that's the flexibility that Fonar gives you. And again, if you want to use application layer, you can just create a separate application layer and you don't even have to change anything in Fonar. Your application layer can talk to Fonar, grab it all and then serve it back to other stuff. Like front end client applications, or you really don't need to move your data. You can use the Fonar driver if you decide to migrate. So yeah, so those are all the other stuff that you can do. So extremely powerful when it comes to like data manipulation and writing business logic that are data-driven in your database layer.
12. User Authentication with Fauna
Learn how to implement user authentication in Fauna, including email password authentication. Fauna encrypts and securely saves passwords, ensuring data security. Explore the simplicity of implementing authentication directly in Fauna without relying on external services. Get ready to dive into user authentication.
All right, okay. So we learned about GraphQL, learned about how you can pretty much create schemas and upload it to Fonar and how it will create a GraphQL layer for you. You know, within like five minutes, you can get up and started with a custom GraphQL backends with Fonar. We learned about how you can create a custom resolvers, how you can create a custom resolver and have your own business logic and query data the way you want it. So now in the next part, we're gonna learn about user authentication. And Fonar allows you to do user authentication with Auth0, with Okta and bunch of other services. But you can also do a very simple authentications like email password authentication with Fonar like directly in Fonar. Just because it's a database, so you can pretty much save your data, yeah, you can pretty much save your data and you can do email password authentication and Fonar won't even save the plain password. So it's gonna be encrypted and saved in a secure way. So we're gonna take a look at that. So, yeah, that's the next section.
13. Implementing User Registration in FQL
Let's dive into user authentication. We'll create a custom resolver in FQL to register users. The registerUser function takes an email, password, and username, saving the user information in Flutter. Passwords are treated as credentials and not revealed. We can test the login function using Fonachelle in the shell. The password field is not explicitly saved in the database, ensuring security. You can find more information on our GraphQL workshop website and download the schemas separately. We'll make changes to the schema and connect the user-defined function to a mutation called register owner, which takes an email, password, and name and returns an owner type.
All right, so let's go ahead and dive into user authentication. All right. Okay, so first let's talk about registering a new user. Okay, so so far all we did is we didn't leave our schema and we just created a custom result or function. Now, let's take a look at how we can create a custom resolver in FQL that will allow us to register users. Okay, now this function is a function that takes an email, password and username and then saves the user information in Flutter. Here, you'll see that there is a credential field. So by saying that this password is a credential, Fauna knows that it's a password and it shouldn't be revealed, okay? So that's very important because you don't want your passwords to be revealed, right?
Okay, so registering a new user, so let's go ahead and create a new function and call it registerUser. So let's go to a function, From this create a new function, it registerUser, we had to do this, copy this. All right, let's say it over here. All right, so query and Lambda, these two keywords are just used to define the function. And here you have an array of arguments. Alright, so email, password, and name, these are the three arguments that is passed in this Lambda function. Creates, so create keyword, we're defining that, okay, we wanna create something new, we're gonna create a document. Collection, which collection, we wanna create a document in the owner collection. Credential, so, and then this bracket, in this part, we're just defining, okay, how we're gonna store the data. So first, with the credential keyword, we're saying, okay, password, there's a password field, treat it as a credential, and then the rest of this is data, so treat it as variable, email variable and the new variable. All right, so let me take a look at here. Okay, all right, so, let's save that. Okay, so now, I'm gonna show you something called Fonachelle. So we created this user, registered user function. Now, we can go ahead and create a mutation and add the mutation and call our GraphQL but it's kind of a hassle to upload the function every time. I just wanna test my login function pretty much. So how do I do it? So I can just go to shell here. Let's go to shell. And here, I can call that PDF, okay. All right, so I can do it with Paul and then the name of the function. And I think we had, so email, password, and first name. It's going to cheat a little bit. And pass in the array, so this is, okay, so this array is mapped to these parties. So now we can kind of make that connection now. All right, okay. And now, let's run it. It is successfully saved, so let's verify. This is our data. And as you can see, you're not gonna see the password field. So just because we defined that the password is a credential type, while you can see the password, that's password 123456. Just because we defined the password credential type, it's not saved explicitly in the database. So if I wasn't smart enough to know that, okay, this is a credential, then I'm gonna expose it. All right, awesome. Okay, so if we have that, and by the way, everything that I'm talking about in this workshop is going to be in our GraphQL workshop website, and we're gonna be continuously updating this and refining it. So feel free to check it out after the workshop, everything is there. We even gave you guys the ability to download these schemas separately if you wanted. So for example, this is just gonna download schema up to this point. All right. All right, so... Okay, so you guys know the drill, so we're gonna create, we're gonna make some changes in our schema again and hook that UDF user defined function to a mutation. Right, so, just copy and paste it. All right, so, excuse me. All right, so we're gonna call it register owner. We're gonna give it an email, which is a string type, password also a string type and a name. Okay, and it will return an owner type. And we have the resolver keyword, just like before. And then the name we're saying, this resolver is going to map to the register user UDS. And that's how it's gonna work. That's how we do the connection. All right, so let's save that. All right. Let's go back to the GraphQL. Replace this to that again. There it is. Awesome. So now, there you have it. So you have the register owner. Two terms of owner type. Okay, so I'm gonna close some of these. Wait a moment. Okay. So, put in the new mutation. List the owner.
14. Creating a User Login Function
In this part, we create a new user login function in Fauna to allow users to log in. The function uses the query and lambda keywords to define the function and specify the arguments. We also use the let keyword to construct a structure and store the result in the credential variable. The function matches the index to find the user by email and runs the login function on that user using the provided password. The login function returns a credential, and we can define the validity of the credential using the TTL parameter. Finally, we select the secret from the credential and return it as the result of the function. Now, we can test the login user function.
15. Exploring User Authentication and Access Control
In Fauna, we can create roles and apply attribute-based access control to provide fine-grained data access to users. The secret generated during login can be stored in cookies or session parameters to communicate with Fauna through GraphQL. We can apply access control roles to ensure users can only access their own data. For example, if I create five stores and John creates two stores, I shouldn't be able to edit John's stores. We'll explore how to log in with GraphQL by creating a login mutation and defining the resolver and return type. Once logged in, the secret can be used to access resources in Fauna, while non-authenticated users are blocked from accessing other resources. We'll continue building on this foundation, granting different access levels to different users. This concludes the review of our backend progress, which includes stores, owners, various queries, and the use of UDFs in the Fauna ecosystem.
Just like before. So we're going to test it with user we previously yeah, using we previously registered, clear this console. We run this and you can see that it generated a secret. It generated, well, gave you like how long the secret is going to be valid for, and gave him back your email address. That was used to log in.
Now, in Fauna, we can create roles and we can, we have this idea of ABAC. So attribute attribute based access control. So that allows the user to have fine grain access over your data, like over their data. So using this, like we can apply some certain rules to this secret. So this user can only access certain data, for example, their own data. Okay, so we're gonna take a look at that in a bit. So this is what the secret is for. So you can, if you're building like a client side application, like a Next.js or a React or a Svalt view application, you can store the secret in, as in your cookies or as your session parameter. And then you can use that to kind of talk to, you can use that to talk to, talk to Fauna through GraphQL, and then you can get resources back. And we're gonna see like how we can apply certain roles, certain access control roles to make it as fine-grained as possible. So just to give you an example, let's say I create five stores and John comes here and he creates another two stores. I shouldn't be able to edit John's stores or vice versa. So once we apply those rules, apply the roles, if we will see that a user with certain access can change certain data, and we're gonna dive into that once we start creating our Next.js application. Okay? All right, so that is that. Okay, so now let's see how we can log in with GraphQL. So again, let's go ahead and create a new mutation. So we're gonna call it the login mutation. And the drill, call it a login mutation. We define what can a resolver this maps to, in this case, it's coming to be the login user. And we define a type, like what kind of object it's returning. And in this case, it's custom object type, so embedded type. So, just gonna copy that. There you have it. And chose TTL secrets. Okay. All right, pretty cool. Now I can save it. Go back here, replace this schema. Replacement schema. We should have a login function right here. Let's create a new one. Application. Login. Login. Obviously. Weíll just use this one. Perhaps, this one. Oops. Let us load. And. So that's it. Okay? There you have it. So now I'm logged in. My secret is returned. So login is just this one mutation call, and once the user is successfully logged in, secret is generated, and using that secret, you can call other resources in FogApp. So we'll block every other secrets, sorry, we'll block every other resources in Fauna for non-authenticated users. And when the user is authenticated, you can give them access to certain resources. And then we're gonna keep building on top of that. Like, some user have some access. Other users will not have certain access. So, yeah. So, alright. Awesome. So that's good. Okay. Now, let's go ahead. Alright. So that's that. And let's go ahead and kind of review what we did so far. So we're still working on our backend. And pretty much at this point, we have a foundation. We have a pretty good foundation for our backend. We have stores, stores belong to owner. We have different types of queries. We've looked at how we can list owners, count stores, find owner by email, how all this, the whole Fauna ecosystem works with UDF and things like that.
16. Creating Front End Application and Authentication
We're going to start creating our front end application and hooking it up to the GraphQL backend using Next.js. We'll install Apollo Client for GraphQL and define the Apollo configuration in Apollo Client.js. We'll create a new public token and a limited-access role for user authentication and registration. Then, we'll create a key based on the role we just created.
We saw how you can create log-in functionality without any libraries. Yeah, so it's already a true user, logging user, saw some FQL stuff. And in the next section, we're gonna start creating our front end application and that's when we're gonna start hooking this GraphQL back ends to our front end application. So, let's go ahead and start doing that.
So. I am going to go back over here. Chapter two. All right, so let's create a client application. Okay. So, we're gonna be using Next.js for this demo. You can use Reacts or any other framework. These steps should be fairly similar, right? So, I'm gonna create a new Next application. So, let's wait for it to finish. Whoops. Cool. So that's done. So let's go to... Let me just change the name to... All right. Let's install. Not sure why it's continuing... Alright, so let's... It's a fresh Next.js application. Let's run it. Let's see if everything's working as expected. Let's go ahead and boot this up. Okay, everything's working as expected. Alright, let's go ahead and install Apollo Client for GraphQL. Save. So, if you have works of Apollo GraphQL client, this should be pretty familiar to you. It's not experimental, it's pretty easy. Alright, so. While that's doing that, I'm going to go here and create a new file. I'm going to call that Apollo Client.js. And here, we're gonna define an Apollo configuration. So, we'll just go over what the code looks like. So, we're bringing in the Apollo Client, we're bringing in the create-http-link-runway-cache and all that stuff. Here, in the URI, this is where it gets interesting. So, our FAUNA database is in the Classic Region, so that's why we defined it as refql-fauna.com slash refql. If it was in the US, it would have been using the US keyword,.us. EU, we have to use EU if you're in the European region. Alright, so that's that, and here we're just doing some configuration in the authorization header, passing in the authorization header and things like that. Okay? All right, so next.
So Authentication in front end. Okay, so first of all, now, like, all this authentication stuff comes in. So first of all, we've got to create a new public token for our application to talk to the PhonographQL, right? So we're going to create a public Phonathesecret, and again, this secret will have very limited access. Ideally, it can only do two things. One, authenticate your user, or register a new user. Okay? So that's what we're going to be doing. So let's go ahead and create this new role, okay? So we're going to go to, we're going to go back to the file. Select roles, create new custom role. And let's see. Okay. Front end role. All right. Front end role. Okay. So here, let's just close these tabs. So here in the functions, we're going to give call access, register access. So we're going to give this role, the ability to log in user. It can call the login function in Fauna and register user. So it can call the register user function in Fauna. And again, if you take a look at the GraphQL schema, so using that key, you can only call these two mutations and you shouldn't be able to do anything else. So that's what we're defining to this role. OK? So I'm going to save it. Now we're going to create. So now we have to create a key for that. So let's go over here and save this. We'll create a.env.local file to store our local dev environment variables. And now, the role we just created, based on that role, we need to create a key.
17. Creating Roles for UDFs and Testing
We're creating roles for our user-defined functions (UDFs) to tighten security. The roles restrict access to specific UDFs, such as register and login. We map the roles to the UDFs to ensure they can only be called by the designated keys. We test the setup in the Fauna shell, running as the front end role, and confirm that it works as expected.
So let's give it a front-end. And that's there. And it generates a key for us. And again, using this key, we can only do two mutation, which is log in. And it's turning it off. All right. Save that. Let's go back over here. OK. So while we do that, I'm going to define it. OK. So creating roles for your UDF. OK. So let's go back to our app. So we're going to create a role for our UDF. So using this key, we can only call that UDF. Register and login. So let's go ahead and create a new role. So register user UDF. Register user UDF. The privileges. We have OMA. The CDF can be. Oh, no, no, no. This register you can only create. Log in, you can only. Let me just make sure I'm doing this right. Let's see, let's save that. Now, back to our function, register user. So in the role, we can now map it to the role that we created. So, here, we're just tightening up the security, just so like, you know, we don't want an authenticated user or we don't want this key to be used other than just calling register user UDF and login user UDF, okay? So that's what we're doing here, so here, this is defined as that. Okay, this is gonna a strictly map into this role, this is register user UDF, okay? So now, let's save it. Okay, so now, what we can do, just to make sure that this is actually working and we actually set this up correctly, we can go to the Fauna shell again, and here, go and try to register another user, however, this time, we're gonna run as, we'll select front end role, okay? So front end role, we're going to try to run it as front end role, so basically, it's going to adhere to this key, okay, so, we have it, so it worked, so that means this is good to go. And if I tried to run anything else with the front end role, it's not gonna work. So, let's...
18. Creating Login User UDF Role
Let's create a new role called login user UDF for the login UDF role. This role will have read access to owner production, as login only requires read access. We follow the principle of least privilege for security purposes.
Okay, so let's go ahead and do the same thing for login user, so, for the login UDF role, so, let's go ahead and do the same thing, so we're gonna go back to our security roles, create a new role, call it login user UDF, again, we're tightening up the security, so, like using that key, and then we can only call these functions and nothing else. And this one, this only has read access to owner production, because this is login and to log in you need to have only read access, you don't need to have anything else. Yeah, so we always follow the principle of least security, sorry, the principle of least privilege for security concerns, so yeah.
19. Client Setup and Authentication
We need to give access to the find owner by email function. Let's test the front-end role and create the Apollo provider. We have a dummy login mutation to test the application. The login mutation successfully fired, and we made a GraphQL query to FAUNA. The client setup is complete, and now we can proceed with proper authentication.
All right, so, all right. Here, we also need to give access to the find owner by email, because our UDS, if you can remember, actually uses that to match, uses this function to match the user by their email address. The indexes, I'm gonna just double check this. I always mess it up. So, yeah, and the indexes find owner by email, I found my email, and I only want read access. I have it, I only want read access. And let's save that, so that's your function, so I'm gonna, oops, go back to my functions.
Here, login user, I only want login user UDF to map to that role. Okay, so save. Now everything should be good. So, let's test that out as well. As well, so let's go ahead, back to the shell, back to the shell. Test this out, just front-end role. Yes, that's it, so that means now front-end key can only, can only perform this operation. That's exactly what you want. Again, this is going to be exposed to, exposed to the interwebs, because it's a public key. So, I want to have least privilege possible for that role. All right, so, okay, this is just showing us how to create the key. We already did it. Put it in the local environment. All right, so, that's that. Okay, so now, let's run our application. So, we just have to create the Apollo provider and wrap our reactor components with the provider. So, let's go ahead and do that. Let's make sure everything's working first. Okay, it's working. Let's go back to my code, going to add that JS file. So, all right, so, we just bring in the Apollo provider and the Apollo client library. Bring in the client. Bureau. And, Apollo Client, and then we import CSS, since CSS over here. That's about it. Have we created the client? Oh, yes, we have. But this is the client, let's store. Okay, something's off. So of course, this is in the wrong directory. Okay, that's something stupid. All right. Let me just delete this. So, we go into the pages, because. So now, if I find it. Yes, I can't find it. Can't find the word I was scanning. So that's, okay, cool. All right, awesome. So now we are ready. So let's see if our application's running. Okay, it's running as expected. Okay, and replace contents of Gx.js with this. All right, so here we're just, just have a dummy login mutation. And, you know, when you land on the page, it just logs in to this hard-coded email and password just to see if everything's working. So let's copy this, and we're gonna replace this anyways. So let's bring our pages index here. So we're just gonna replace all that. All of this. So here, we have a button, onClick, just do login, and here I'm using the security of the users that we created previously on the password, just to test everything out. So let's go ahead, yes. There we go. And as you can see, the login mutation fired. Let's do that, okay. And here you can see that we actually made a GraphQL log. So there's GraphQL query to FAUNA a lot this brand the owner login, mutation, this, okay. So, so far our friend in the application is not connected to FAUNA. Awesome. Okay. All right, so that's, that's all for client setup part. Let's go ahead where we left off. All right, so we got login sort of working well login sort of working well, cause we don't have any input or anything like that yet. But yeah, so the client setup is done. So next let's go ahead and do proper authentication.
20. Creating User Signup Page and Mutation
In this part, we create a user signup page using UIKit for styling. We create a signup component and a signup page, familiar to React or Next.js users. The signup component includes a simple form with input fields for username, password, and email. We also define a signup mutation using GraphQL to sign up the user. The complete code for the signup page and mutation is provided. The signup component is styled using global CSS, and the signup mutation is executed on form submit. The complete file includes the necessary imports, GQL definition, and useEffect hooks for form submission.
Okay, there you go. Okay, so our application is running. Let's go back over here. Refresh this. Oh. I don't have anything else in there yet, but it's okay. Let's create our user signup page next and here. Okay, I do have the styles defined here as an example, so this should be fine. All right, so let's create our user signup page and if you're familiar with React or Next.js, this should be really familiar. So, first of all, we're going to create a new components folder. So, let's go ahead and create a folder and create a folder for components, directory, let's create a folder for components. Let's type components, we can create a signup component. Let's go ahead, create a new file, signup.js, signup.js, oops, there we go. Signup.js, we're just going to bring this in here.
Okay, so let's go over to the code quick. All right, so here we have a signup component. This is a simple form components with input, signup, user names, password, email, and a simple form and some state to handle the form states. So that's pretty much it for the signup form components. Then we're gonna create a signup page, so we're going to create, so we're going to go here and pages, and create a new file. We'll call it signup.js. It's still here, we bring in the signup component from the signup form component page. So now save that. Now if I go back here, let's get the signup. I have it, so it's working fine. I think there, it did have some global styling, just in case to make it look more presentable. So I'm just going to get that here. And then this is all going to be included in the example repository or you can choose not to. Or in the CSS, just to, yep, there we go. All right, so, signup component, it's done.
All right, let's see. Okay, so now, let's take a look at the signup mutation. So this is the GraphQL mutation we were doing to sign the user up, so owner signup. Also register, register owner, like we have seen in our GraphQL, right? So register owner, this is the one that we want to execute from our front end. Okay, so from here, and on submit, on form submit, we have to execute this register owner function, okay. So let's go ahead and do that. So here we can, it's just, okay. So okay, I'm just gonna go through the code quick. So here we have the register owner function. We define it as a GQL, and we're again, using the graphical client. And then what we're doing is on use effects. We are looking for the data. So basically, when we, submit the form, it does the do, it calls the do sign up function. And then it tries to sign up the user, it tries to sign up the user by calling the sign up user function. And it's using the user intuition from FQL, from Apollo account, okay. And the whole file, the complete file will look something like this. So let's go over it again. So basically, first, let's just bring in the draft documentation. So it's like, right here. And then, we define the GQL. And then, we just do a usedEffect. And then. Scoring. And then, we do a usedEffect. And you can see here, what the outside object. And then, if it's not loading. So, sign up. It has a state, so if it's error, it just shows something like that. Oh, we have to find the location here. So, right here. Not here.
21. Session Management and Cookie Handling
Let's go ahead and register a new user. Now, if I go back into the collection, a new user has been created. Let's create a login form next and call the login function from the front end. We also need a Login.js file in our pages. So now we can go to the login page and check the network tab for the secret and TTL. In the next section, we'll explore how to save the secret in a cookie session and use it to interact with other Fauna resources. We've completed the authentication section, allowing us to log in and register new users using the public key. Now, let's move on to session management using the just cookie library. We'll make changes to the login.js file to set the cookie and verify its data using JSON. After making the changes, the file will update the useEffect hook. This concludes the section on session management.
Let's go ahead and error. Okay, so that's that. So, it does have some, okay. There's the assignment at five. All right, so let's go ahead and shut this out. So now we need a user probably. So let's, let's try to register a new user, so. Four. Oh, great. So now a new user has been created. So now, if I go back into the collection, file C, CE 4, that's here. Okay, so that's it for our signup form. All right, so let's go ahead and create a login form next. And we're gonna use this in a pattern, pretty much. So we're gonna have another login page and we're gonna log in form. And then, you know, call the login function from front end. Okay, so create a new file to log in. Folder, here we go. And again, you kind of have similar like use effect using location and here we're just using the login function from login mutation from our GraphQL schema. All right. And that's about it. And we have similar user mutation data loading, some states to control the phone state. Here we have a single session to do. So we're going to get back to it later. So once the, once you get the secrets, we want to save it in our session cookies. So we're going to take a look at that in a bit. So do login, just runs that function. That's that mutation using Apollo Graphical Client. So. Alright, so that's that. We also need a Login.js file in our pages. So under pages, go to Login.js, and there we just bring in the Login.js component. So it's done. So now we can go slash. You can do the slash in like that, and then we'll just do the login page popup. So right here. So Login.js popup. Alright, and what we can do here is... Oh. I'll try to log in. Message and check the network tab. You'll see that I'm here, it is login. Let's just, okay, we'll visit the real data. All right, so we're getting back to secret, we're getting back TTL, all that good stuff. So, I think we can also go back to email. Let's try that. So we're gonna go back to sogregs. Email. Something, anyways. Ah, there you have it. That's how you get that, yeah. So, and this secret is what we have to save in our cookies or however you wanna handle the session. So, in the next section, we're gonna take a look at how you can save this in your cookie, as a cookie session and use it to interact with other Fauna resources. So, let's go ahead and jump into that. All right, so, that's pretty much it for this section, like authentication, we created the forms and now we can call the GraphQL mutations and now we are able to log in our user and register new user using the key, the public key that we created. Now, the public key doesn't have any other access, so we cannot get the stores or run those other queries or mutations using the public key. Okay, all right, so now, I am going to go to session management. Let's take a look at how session management works. So, we're gonna use just cookie, so let's go ahead and install, dependencies for that. So we're gonna use just cookie to manage our session. All right, so, components. Okay, so we're gonna make some changes to our login.js file. So here, in that to-do part, we're gonna set the cookie and call it FANA session. JSON is to verify all the data of that cookie and make it expire based on the TTL, the Time to Live parameter that we set in FANA. So let's go ahead and do that. So after you made the changes, this is how your file will look like. So basically, all we did is update the useEffect and yeah, that's pretty much it. So I'm just gonna copy this, the whole thing. If you wanna look at the difference here, we're only adding this in the useEffect. So I'm just going to copy the whole thing.
22. Front End Session Management and Querying Data
In this part, we create a new component called dashboard to handle session management in the front end. The dashboard component retrieves the session cookie and redirects the user to the login page if no cookie is found. We also skip the front end part of automatically logging in users after signup. The session management ensures that users are redirected to the login page if the secret is not present or the cookie expires. Now, let's move on to querying data in the front end and exploring attribute-based access control in Fauna.
Again, this is just front-end code, so I'm just gonna copy it, run through this quick. Copy this whole thing. So here in the to-do section, now we're setting the fauna session cookie. Setting the time. And then once everything is set, we just kick the user back to the root directory, okay? So that's that. All right, so let's create a new component. So right now, if you go to our root directory, there's this one logging button there. It's not running. So yeah, we don't want that. So we want to have like a dashboard component. So yeah, we don't want to have that there. So let's create a new component called dashboard. So here, component, dashboard, let's copy that. So here, just have like simple useeffect React router next and just bring in the cookie. And here we're just retrieving the cookie, the session cookie from our cookies. And if there is no cookie found, that means that the user is not logged in. Just skip them back to the log in page. And just return the step and just use that dashboard. All right so let's save that. Let's go back over here. Let's refresh this. Oh we didn't plug that into, we didn't plug that into our root folder. So let's go to index.js. Let's go here, and we want to get rid of all that. Let's just have this as great. So all we're doing is just removing that dashboard component in our index.js file. Let's close everything else, let's go back to index.js. So just because I'm not logged in, I got kicked back. Let's move the login folder, which is exactly what we want. So that's good. So, again, some more front end changes. So after user signs up, and so this is just the same thing, so after, oh so this is just manually signing up. When user signs up, just manually add them to, log them in right after user signs up. I'm not gonna do that, I'm just gonna skip that part. Yeah, we can just sign up user and then manually log in. So let's go ahead and try doing that first. Okay, so, let's scroll back up. This is where we left off. Okay, so let's go back over here. Okay, there you go. Now we're back in the dashboard and now, if we go into the application, the cookie, you'll see that there's a Thonus session right there. And you'll see that the secret is being saved over here. Okay, so if the secret is not present or the cookie expires, then we'll get back redirected. We'll get user, get redirected to the login page. Okay. So that's what we did there. Now here is also some more front end code that I previously wrote. So when user signs up, you can just automatically log them in. I think for this workshop, like you can definitely feel free to try that once you have the link. Like once you go over this by yourself, definitely try doing that, but I think we can just skip that part, that front end part for now. So skip that and go ahead and create... We already did this, we can go ahead and... Okay, we already did this. Yeah, I think that's about it for session management. So let's go ahead and see how querying data works in the front end now. This is where all the interesting stuff happens. So, we talked about ABAC and attribute based access control and FAUNA. We talked about how you're only giving certain access to certain users.
23. Querying Data in the Front End with Access Control
In this section, we explore querying data in the front end with fine-grained access control. We create a new role called the auth role, which grants read permission to the store and owner collections. Additionally, authenticated users can find a user by their email and access the stores that belong to them. We switch to the membership tab and add the owner role, giving logged-in users the privileges defined in the auth role. We make changes to the dashboard component to retrieve the user's information and associated stores. Finally, we populate the dashboard with the retrieved data. This concludes the section on querying data and access control in the front end.
It pushes you back, it gets you back to the log in page. Okay. So the only part we are skipping is the signup validations. So feel free to go over that. Yeah, I'm not gonna do any form validation or not gonna go through all the front end code. Just for, just so we can get to the more important part. All right. So that's about it for session management. So let's go ahead and see how querying data works in the front end now. This is where all the interesting stuff happens. So, we talked about ABAC and attribute based access control and FAUNA. We talked about how you're only giving certain access to certain users. And we're also, we also saw how all this sort of works in a broader context. So we saw how we created UDF, how we created roles so that our front end can only execute certain commands or certain functions and FAUNA access certain resources and FAUNA. So if you want to learn more about ABAC attribute based access control and the whole, if you want to learn more about how everything the fine grained access control works, feel free to do some research, feel free to read some blogs and FAUNA blog. Feel free to reach out to us. However, in this workshop, we're gonna apply some of the things. We're gonna apply the main meat of it. We're not gonna go too detailed into ABAC, but we're gonna apply like the very basic idea of it. So let's go ahead and see how querying data works in terms of fine grained access control. All right? So that's what this next chapter is all about.
Okay, so we're gonna have to create a new role and we're gonna call it the auth role. So when user is authenticated, they get assigned the authenticated role. So let's go ahead and create this new role. So I'm gonna go here, create new role. I'm gonna call this role auth role. And here I can close that. Okay, so here in our auth role, we're gonna give store and owner read permission to store an owner collection for the auth role. So let's go ahead and do that. So add store owner, give both of them read permission. And then we also want the authenticated user be able to find a user by their own email. Like if you're trying to find yourself by your own email address and get all the retrieval of information, you should be able to do that. So find owner by email, you have to be able to use that. So we're gonna give read access to that. And you should also be able to find the stores that belong to you. So, this is the relationship constraint. So we're gonna also read access to that. And then, we're gonna switch to membership tab. So, this is where things get interesting. So membership tab, and we're gonna add owner. So this is telling Fauna that when a user is a owner, when a user is an owner, and when you're applying that login function, give all the logged in user this auth role, and all the logged in user, well, give all the logged in user the privilege to call, this thing's to read store, read owner collection and use these indexes, right? So that's what's happening here, so we're gonna save that, save this, and our new auth role has been generated, and now, this key that we created when we logged in a user, the secret has all the all the privileges of this auth role, just because, remember, auth role is a member of owner, so every time we run that owner, login owner and get that, retrieve that key, that key gets all the privileges for these defined privileges. For example, right here, see like that, read roles and all that stuff. All right, hopefully that's clear. Okay. If not, like we, I kind of indicated here in the workshop like how they're kind of word together. All right, so let's go ahead and make some changes to our dashboard component again. So in our dashboard component. Now, when a user is logged in, we want to find that owner or user by their email. Then we want to get the user information name, email and also all the stores associated with that user. Okay, so that's what we're gonna do. So we created a new query. And then we execute this query if a session is found. So let's say if cookie session is not found, let's kick the user out. But if cookie is not empty, that means the session is there, try to collect the user email from the cookie session. So just a console log from debugging purposes, not important, and then get the current user. And to get the current user, actually we'll execute this query. And once we have, have that, we're gonna have the data back. Once we get the data back, we can just populate the user information name, user store, all that stuff in here in the dashboard. So, all right, so here I have some object keys and store that are just mapping to looping over all the objects. So if the owner or the user have multiple stores, it's gonna loop over all of them and we're gonna print them in our dashboard. So that's pretty much what's happening here. So I'm just gonna copy this again. And just because of the time constraint, I'm not gonna write everything from scratch on these dashboards. So, let's just copy and paste it. So, and there's an error somewhere. Okay. Okay, all right. All right, so now, once we do that, let's run... Let's work out. Okay.
24. UI Refactoring and Permission Issues
Let's do some UI refactoring by creating a map bar component and a layouts component to wrap our pages. We need to set the session token properly and check if the cookies are set correctly in the login. We are experiencing permission issues and need to investigate further. If you have any questions about roles or authentication, feel free to ask.
So we have this thing. All right. And we'll see the network all of here. AURL mission denied. Okay. So... We've got email. I'm not gonna be able to call that. That's okay. Yeah, I think the session till then kind of expired. So that's fine. So let me just do some UI refactoring. And just bring in the map bar first so we can actually log out and log back in. Let's go ahead and create some UI refactoring. Let's go ahead and create a map bar component. So let's go ahead here. And wrap our JS. So again this is just links and a logouts button. You just destroyed the user session pretty much. So let's do that. And then I'm also going to create a layouts component. It's just because, to wrap all our pages in that layout. So let's go ahead and create a layout.js file. Just copy paste here. So this is important the navigation and then here we have here we have here we have the navigation bar component that could be implemented. Okay we'll see. And then, okay and here I just wrapped them. So I wrapped everything with the layout, so here the index file is wrapped with the layout Cool So let's see Forward This is giving me so I'll import everything here we go Perfect So here I know we have that OK that means Bendmerica Awesome So let's log this user out OK still got no permission to do that OK, so is it actually using a proper OK, so this is the EdShell I'm just go ahead Yeah, it's using the he's in the wrong key. It's not using the key from the session token. Cookie So here, I think we have set the session token properly. Let's go back over here. So Time search. Set the cookie somewhere here. Give me one second. I feel like in Apollo... Ah. I feel like we have not set our cookies in login properly. So. So... What's that? Oh boy, okay. Um... Let's do that somewhere here... Right. So... Let's go ahead here. Maybe we have to restart? It's always using this, okay... HSL Interface Oops... Okay... So, looks like we are using Bit-O-Lite, Secret, just this one. Okay, not a problem. Let's go back to the dashboard. I'm gonna take a quick look in the notes here. Let's start with this. Let's open this up. Still have permissions denied. Okay, so technically what we have to do here So, why do we do that? How do we do that? find subheaders. Okay. Karen Dotson. Okay. Each props. Okay. I'm not really sure why that's not setting the header and Apollo client. That's just what we figure it out. If you guys have any questions in time about roles or authentication, let us know. Thank you. All right, so I think we have messed up something here, so I'm just gonna pull up some of my barcode, cuz it's too inconsistent. This is one that does not provide anything so let this one... By the way, seems to do it for from this, which is great because this is the one that was private and workshop repository as well. Let's go ahead and put it right here. Yup.
25. Full Cycle of Authentication and Resource Access
We logged in the user and obtained a secret token, which is used to access other resources in Fauna. The roles and membership determine the privileges and access to query owner data. This completes the full cycle of authentication and demonstrates the capabilities of Fauna.
Okay, so now, it's working. That's kind of weird. Okay, so, I don't know. Probably had to restart. Yeah, probably had to restart the server. Yeah, so, yeah, I would probably check Apollo caching. There's probably something wrong with the caching. But yeah, so now, we're getting the user back as well as all the other data and the store associated to the user. And user information, we're getting that back as well. So, yeah, so that is pretty much the full circle. Kind of come full circle. So, you learned how the ABAC or the secret token is being used to call the user, to call to get the user access. So, yeah, so pretty much coming back full circle, we logged in the user and then we got a secret token and then using the secret token, only using the secret token, we can call the other resources in FAUNA. Okay, and so all our roles are set up here and our membership is here. So based on the membership, we, FAUNA knows that what kinda secret token is it going to generate and based on that, it knows what kind of access it has and what kind of resources it can query. So based on this privileges, you will see that it can query owner data. Okay, all right. And not quite sure why both client cached that data, but yeah, so that's pretty much the whole cycle of a back and how you can do different things with it.