React/Node.js Microservices App With Docker and GraphQL | Lucas Chen | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

React/Node.js Microservices App With Docker and GraphQL

teacher avatar Lucas Chen

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

10 Lessons (2h 37m)
    • 1. Introduction

      0:51
    • 2. Creating The Basic App Structure

      12:16
    • 3. Setting Up The Database

      18:26
    • 4. Setting Up The GraphQL Server

      20:03
    • 5. Setting Up A Mutation For Creating Users

      18:54
    • 6. Authenticating Users Using GraphQL

      17:19
    • 7. Fetching The User Session Using React

      24:49
    • 8. Storing The User Session In Redux

      10:43
    • 9. Logging The User Out

      15:02
    • 10. Adding Listings Using GraphQL

      18:47
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

210

Students

--

Projects

About This Class

Learn how to build a microservice-powered full-stack React app from industry professional Lucas Chen. All steps are explained in detail, and you can easily follow along at any skill level (although some basic experience in Javascript, React and/or Node.js would help!)

Meet Your Teacher

Teacher Profile Image

Lucas Chen

Teacher

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hello and welcome to my course. My name is Lucas and I've been working as a web developer for the past 12 years. I currently run that accordion Academy where we help people find jobs in the web development industry. Or if they're already a web developer, help them find a job with a higher paying salary. In this series, you will be able to follow along with me to not only build something awesome, but also understand exactly how it works. Some of my favorite tech includes JavaScript, React, NodeJS, graph, QL type script, AWS, and Docker. So you can expect more classes from me in these areas. My classes are for you. If you want to build high-quality production ready applications, you want someone to cut the crap and get straight to the point. And you are tired of watching videos at two times theta. I hope you enjoyed this tutorial and I wish you the best of luck in your professional career. 2. Creating The Basic App Structure: Hey guys, this is Lucas from better Coding Academy. And in this video we are going to be putting together a microservices application. So it's going to be a pretty simple application, kind of similar to a very basic gum tree. We're going to be able to have listings and we're going to be able to have users sign up and also login to the website as well, and just be able to post listings once they logged in. It's comparatively very simple, but it's really just about the architecture. And I want to show you how I structured that for this project. So we're going to be using NodeJS for the backend and react for the front-end. And in order to work with these components, we are going to be using Docker compose. So now let's jump straight into it. So the first thing we're going to do is just open up Alice hominoid over here. And we're just going to get a couple of directories into here. So the first one we're going to do is put an API gateway. So let me explain what the API Gateway is going to be. So essentially inside of our application and you shouldn't see a diagram pop up on the screen about now, which I will add in, in post-production, is we are going to have this diagram. So we're going to have an API Gateway. We're going to have a classifieds app, which is going to be for our frontend. We're going to have a listing service and also a uses service. So you notice that we have two services here, essentially a listing service and a user service. And these actually connected to the classifieds up via the API gateway. So the API Gateway is responsible for controlling the data flow within the backend of the system. It also helps to keep all of our authentication in one place. Just basically managed essentially the business flow for this particular application. Now a quick disclaimer. In the case of Microsoft, this is the architecture can really vary between company to company. It can also vary between different use cases depending upon the actual design that people want to go for. In this case, my design is far from optimal. Even in my opinion, I feel like there are many things that I can improve upon. And also for the interests of time, I have actually chosen to take a few shortcuts, but without, in my opinion, sacrificing the quality of the actual microservices architecture itself. So going to have API Gateway and we're going to have another directory called classify as f. This is going to be our React app. We're going to have listing service, which is going to be for our listing. So it's going to manage all of the listings that go inside of our classifieds app. And we're also going to have it uses service, which is going to control things like authentication and stuff like that. So now that we have these four over here, what we're going to do is let's just quickly set up both the listing service and also the user service because they're so similar, we can kind of do one and then just copy paste that into the other one. And it actually works out really well. So in the case of the listing service, we're going to first do yon in it hyphen y just so we can get it setup Dennis dotted. And let's have a look at this one here. So we should have a package JSON. Let me just put this one over on the right here. And now we're going to add a few basic things into here. So the first thing we're going to add depth dependency is Pebble watch, which we will use to watch. I'll code it essentially, just so that we can see changes locally even within Dhaka. And then we're going to add as dependencies at Babele forward slash, forward slash poly fill at Babele forward slash preset m. And then also I will plugged in and module resolved. And we're going to press Enter. So now that we've added these, let's right-click here and you file, and let's create a Fall course. Babble would all kinda fake dot js. So now inside of this file key, we're going to write into EP module.exports is equal to. I'm gonna put it into the plugins and then we're going to put in a module result as the plug-in here. So remember how we included Babel plug-in module resolver. So that's this one here. And we are going to do alias and then alias hash root two dot slash SRC. And we need to put double quotes around. That's just like that. And we have a Plugins hash route to SLC and then presets, and we do another square brackets and then at Babel for sludge preset n, And then we targets, and then node is current. So basically this just sets up pretty set em in a way that works for our NodeJS. So we have our presets here. I will plug in here, and this is our babbeuda APP_CONFIG dot js. So now inside of package.json under the script section here, now we're just going to go like that. And then we are going to add in a script for watch. So the one-off script, it's going to babble watch and a hyphen L capital L, SLC four slash index.js. Now the reason I use a hyphen L is because this flag basically means that instead of waiting to detect file system events for changing, it actually does a regular pole on the files. And the reason I use that is because I've actually kind of run into issues where it doesn't actually pick up on changes and I had to manually waste on, but I find that polling is just far more consistent. So we do something like this. And then we right-click New File SLC for with such index.js. And we're just going to include something like import path from puff and then do console.log working. And the reason we do this is just so we can say if this line will give us any era which is short, and if it does, that means that Babel isn't working or something like that. So now we have this file here, that should be just fine. It's now everything. We've got our listing service. Now if we actually type a yon watch, we shouldn't be able to just say working on the page here and then we can Control-C that to kind of get rid of that for now. What we're going to add now is right-click on this thing service and we're going to add a Docker file. So as I said, we are going to be using Docker quite extensively fold this project. And the Docker file here allows us to configure Docker specifically for this service. It's not going to be something that we're going to use for the whole thing. That's Docker Compose, which we will set up later on. Our Dockerfile is specifically for this directory. And you'll see what I mean by that is that this Dockerfile is the configuration for this container. So our listing service is obviously, we've designed it to be one container here in that it contains one processor like the NodeJS process. And we run that on a single container. Uses service would have a separate container as would be API Gateway. Now for the classifieds app actually won't be using our container. And the reason for that is I just find running React apps on my own computer is a lot easier. And in the case of production generally, you kinda wanna keep it as plain static HTML anyways. So we don't want to do is you don't want to like have a Docker container and set up a lot logic around that. You generally want to try and keep your React app as minimal as possible. So now we have our docker file here. We're going to add into here firstly going to right from node colon 12. So what this means is that this Dockerfile is based off an existing Docker image and the existing Dr. image is going to be node colon 12. So this one exists on the so called Docker repo. And you can actually come on up like this, which will open in the browser here. So we can open us sin else, just wait for that to load real quick. And this one here, you'll notice that it has all of these are published online. So basically this allows us to extend off of this one which was actually published by the official NodeJS people. So this one quite legit. And what we're going to do is we want you to copy thought to forward slash, forward slash. Now the actual directory you choose here isn't that important, but it is a Linux file system. So you have like we'd folder names like slash slash, GMP slash vowel, that kind of stuff. We're going to use a slash up to here and we're going to copy it into a directory called App. So basically everything inside of listing service goes inside of there. And we're going to do what the I is for such offered slash app. And if we have a look at Work EIRP and sets the entry point for any subsequent ad copies. Cmd and 2 run instructions that follow it in the Docker file. So that's exactly what we're gonna do.py run in yon, and this one runs the command and then we're going to just Cmd yon watch. So this one is the default executable for this container. Now it's a little bit different to run yarn because Ramanujan basically runs it one time when the container is building and cmd yon watch runs at every single time you start the container. Then it does this every single time. And this one runs once when the Docker file is being used to actually generate the container. So we're going to save this file real quick. So now we're going to go over here to the side and time stopped off the dot. So now this will build this whole listing service here and you will see it's running things. So firstly, from NOW 12 copy where FTIR is going through R1, yon John is automatically installed inside of the node js image, which is pretty cool. So kinda does its own thing over here and then it will finish off and then CMD on watch, and it does that. So now we have our essentially our container generated for listing service. So that's pretty cool and we have this one working. But now what we can actually do is copy all of this and we'll grab that so that and then we are going to paste it directly inside of uses service. But obviously we're going to go into package.json, change the name here from listings to users. And we're going to just open up a new tunnel here. Go to uses this Typhaon again just to refresh the yonder locked you could with the new name and all that kind of stuff. And now what we're going to do is we're going to do docker, build dots again. So now it's finished building and we have these two, both done. What we're actually going to do now is just close both of these. And now we're going to create our docker compose file. So I'm going to create it in the root of this project and we have to call it Docker hyphen composed YAML. So this is a YAML file. Yellow is kind of like an extension of JSON and you think of it that way. It's just a, quite a powerful way of declaring configuration. So now we have this funky and inside of this file here we're going to write version is going to be number three. So the different versions have kinda slightly different syntaxes. I'm using version three here. So the first one we're going to add is listing service. And inside of listing service, this one is going to be built using dot slash listings service. So if you remember that we've already built our container specifically for listing service. So now we have a container full that's, and then we're going to essentially use that to run our project. And then this one we're going to write depends on, and we're going to go here and just write listings service db. So what this means is that this one depends upon listing service they need to run first. So it kinda depends upon the database here obviously. And what we're going to do is we're going to leave this like that, but also with volumes. And we're going to write dot slash listing service, if I can spell correctly, is through forward slash, forward slash app. So if you remember inside of listing service here, we actually use forward slash, forward slash app. And the reason that we use this volumes is basically this allows this directory to be syncs with that one so that when we make any changes inside of here, for example, babble watch will automatically pick up on those, even though it's technically inside of a container. So we have the directory mirroring, which is really cool. So now I'm gonna grab this and we're going to go down here and we're going to call this one uses service. So basically everything's the same except this one is uses service here. But you'll notice that we haven't actually included uses service TB and also listing service they be. So we're gonna do that now and let's just add this one here. So this one's going to be our listing service db. And this one we're going to have environments and we have to set a few things here. So this one is going to be based off of the built-in while the public MySQL Docker image. So this delta image takes in quite a few different configuration options in order for it to work properly, including like for example, the root password and stuff like that. So that's what we're going to be doing here. We've got an environment and we didn't MySQL root's password is equal to password. And we're going to do my SQL database. So this is the default database it creates for us, is equal to d b. So now that we've got that, let's do image and we're going to do MySQL 5.7.20. That's the one we're going to be using. And then for the poets, we're going to leave that out for now. Let's just copy this, go down here and let's call this one uses service. The B makes sure you get the indentation right. It's kind of like Python and you have to have them all on the same level here. So make sure you always match his mind before we continue. Uses Service uses service DB listing, service listings, service the bait. So now that you have this, let's go over here and let's close one of these here on the side. And in the remaining one, Let's go back to microservices demo. And inside of here we're going to do Doctor hyphen compose up. So this will run the whole thing here. So we're going to recreate these ones and you'll see that we have both of them running parallel to each other that uses service one and listing service one after both databases are running. And now you see both of them here say working. Now if I go into listing service and I change this working here to start with an E for example. And I save your artist that it automatically changes even though it's inside of the container. And it's the same thing with user service. And the reason that that works is because we have this volumes thing here running. So volumes is really pretty cool and allows us to kind of do a lot more development work here, a lot more easily. 3. Setting Up The Database: So now let's start building out a little bit more of our listing service. And what we're actually going to do first is have a look at this database over here. So we've got MySQL root password equals password database sequence d b, but we haven't actually expose this to the outside world, so we can't access it on L actual computer. So what we can do here is let's just, I didn't keep ports and let's do 0 dot 00 and let's do 7203306. So the reason I do this is because I'm going to use 7200 for this baby and for the other DB is going to be seven to 01. So essentially what I'm going for is like my application will be at 7,001, my API gateway will be at 7 thousand. And these ones here we're going to just publicly exposed for now. Ala databases will be at seven to 0 something and our services will be 710 something. But I'll show that later. So we have this database here, and let's do this one, and let's do seven to 01. So we have these two here. We do a Control C and just let that kill. And let's docker-compose up again, and it will recreate that. So in the meantime, I'm going to get SQL Pro open. And you'll notice I have SQL pro over here. We've got users service DB and also listings service db. So let's have a look inside of listing service dB here. Let's click connect and I'll go down here to DB. And now the database should be empty in terms of the actual configuration, the host, we can just do 127001, which is basically localhost. Our username is going to be root and I'll password, it's just password. Obviously doesn't start here, but PAS SWOT Aldi, because that's what we specified here. So that's the root password for the database. It's optional, but you can write db here if you want. For listing service dB, it's seven to 0 is 0 for the port and for users service dB, it's seven to 01. So now inside of listing service they, but you'll notice that it's completely empty, which makes sense. We're going to add some stuff into this now. So let's keep this one running up here. Let's create a new terminal window, and let's go inside of listing service. So let's go into him. Let's add in yon, add mysql too, SQL allies and also see polis CLI. So we'll be using SQL eyes to kinda handles database stuff. For the sake of this project, SQL eyes is my personal favorite when it comes to ORMs, I find that it's the 1.2x most consistently for me and the one that I run into the least issues with. So that's the one I'm going to use SQL CLI tool in order to run migrations. And you'll see what we do with that. Mysql to is specifically so that we can interact with MySQL databases. So now that we have that out of the way, instead of listing service here, let's right-click and create a new file, and we'll call this LAN thoughts equalize C. So this will be Alice sacralized configuration file. And inside of this file here just write Cons path is equal to require path like that. And we're going to do in module.exports is equal to config, PAF dot result underscore, underscore d ion and that they'll slash sql slash config ab.js. So let me just make this one a little bit smaller. So we went out on one line. Let's put a comma at the end and do migrations puff, and then do path dot resolve understanding throughout the ion name. They'll flash SQL eyes forward slash migrations like that. So now we can now put a semicolon here, save this file. Well, let's put it into JavaScript so we can see what looks like. And that's perfect right there. So now this file, okay. It's going to be our configuration for SQL allies. And with this fall out of the way, you'll notice that we have a SQL eyes directory that when specifying here. So we're going to right-click this new file and we're going to create this. So SQL eyes forward slash config ab.js, and this one goes outside the SLC directory and inside of this file here just right in module.exports slot development is equal to and then dialect is going to be MySQL. Cda storage is going to be a SQL eyes, although we won't really be using this. And then URL is going to be processed on ENV dot dB on the school URI. So we're going to save this here. And you'll notice that we're using Process dot lambda2 EBRI. So we actually haven't defined this on. And in order to define this, let's go into Docker compose dot yaml here for listing service here. Underneath depends on we're going to do environments here. And let's do hyphen TV URI is equal to, and we're going to write my SQL colon forward slash forward slash roots colon password listings service the B for such Amy question about Chaucer is equal to UTF-8. So let me explain what's going on here. So MySQL is the database management system that we're using, is the username, password is the password, and it's going to be at, at listings service db. So Listing Service DB is actually this database here. So inside of Docker, it does this thing, which is really cool, which lets you access other containers inside of Docker compose simply by writing their name. So I don't think that listing service AB, it will automatically referred to this one regardless of the actual IP address which is assigned to it. So we can do that, which is pretty cool. And then we have forward slash the database name, which is going to be JB. Notice how that matches this one here. And then we do question mark the Cha set which is essentially being encoding. We set to UCF H. So that's something that I always use on and it just works well in terms of Chinese characters in times of emergencies. So as to whether or not it actually does anything in this context. A 100% sure, but I think that it's good to have that debt. So now we have our environment, things set up here. Let's grab this one and let's actually put it here for a uses services. Well, it's pretty much the same thing except this one becomes uses service DB, the username and password stay the same. So we use that one there. So now we've got dataURI to find. Let's go back into SQL eyes here, and let's create a directory court of migrations. So this is where we will store all of our migrations for this project. And essentially what migrations are is they represent the kind of changes to the tables and to the database structure that we're going to do incrementally throughout our project. So the first one we're going to do here is right-click new file and we're going to create a file based upon current date and time. So what I'd like to do is like the first lately. So 2-0, 19, and then the month which is December at the moment, and then today's the 22nd. And then for the time we're going to do three or 451 PM. So 150451. And then we're going to do hyphen create, and we're going to call this one listings ab.js. So listings is the name of our table, which is why we do create listings, because we're going to create that table now. So inside of here we're going to write module.exports. Thought up is equal to query interface and data types like that. And do a turn query interface dot create table. And we're going to write listings here. And then curly braces ID, and this one's going to allow null false, auto increment is true. And if I can spell that correctly, primary key is going to be true and the type is not a type integer unsigned. So this is ala Heidi here, and we're going to write title is allowed null, false, type is datatype slots string, question comma again, and then description, and then allow null is false and the type is datatypes, they'll text. So this is how we kind of stole the title and the description are the two main data types are going to be storing here and then comma and then created at, and this one's going to be allowed null, false type is dots. I'll tie it's thought date. If you've watched my video on, on SQL as before in the past, you'll know that these are the kind of SQL eyes timestamps. So we have created at and updated at and we also have deleted that. The only difference is that deleted that is allowing all true. So now codebase, he could erase them, put a comma curly brace again, and we're going to I toss set. And this one is going to be UTF-8 like that. So the Cha set essentially represents the character encoding for this table. So it's actually quite important that we set it to this. Otherwise we can't include cool stuff like emojis because that just kind of breaks the whole thing. So we have this, we have create listings. And now what we're going to do is go into package.json and let's try and figure out a way to actually get this migration run on the table. So the way that we do that is we add in a script. So Scripts here we're going to write db migrate and we're gonna do SQL lies, baby colon migrates like that. Well, what's it going to do one more which is going to be db migrate undo, and this one's going to do SQL, DB migrate undo. So essentially migrate will run all of the migrations that haven't been run yet. And db migrate undo, will undo the last migration that we did. So they soar really quite useful. We include them here. And now what we're actually going to do is we're going to open up a terminal here and we're going to do docker ps. So docker ps basically tells us which ones are commonly running. We can actually open up a terminal case so we can see that more clearly. So let's go here. Let's just do a docker ps, and you'll notice that we have other uses, servers, the listing service, and then we have to MySQL ones, these ones here. So we're going to do is we're going to go into the listing service one. And the best way to do that is to just use the container ID. So what we're going to write here is docker exec hyphen IT, IT stands for interactive terminal. And we're going to grab the container ID. I'm pretty sure in this case here because all four of these have different starting heart is we can just write C1 and will automatically match, and then we just write Bash after that. So now you'll see that we're inside this one here. It's successfully much not because there's only one studying of C1. And where inside at forward slash, forward slash app. So if we do ls here, you will notice that we actually have all of the files for our listing service. And the reason for that is because Ford slash slash app is amounted volume. We covered this inside the Docker compose file. So now inside of here we're going to do yon DB colon migrate. And we're going to wait for that to run. And we actually get an error. And the reason we get an error here is because I haven't restarted my Docker compose and that's completely my fault because we added in these environment variables, this one here and that one there, but we haven't restarted it to kind of enforce those. So we're going to control, see this one here real quick and we'll go into a rerun it. This one will get refused as well. Actually it shouldn't just connect, but on we'll wait for that to happen. Yep, so now it seems to be running. Let's go over here and this one's closed on us. So let's reopen this one and do docker ps. Let's see which one it is. It should be seven C. So let's change this one KD at seven C and then bashed in our inside again. Let's make sure it's working. So we do yon db migrate. And now you see that it did create listings migrating, migrated. So now let's actually go back into SQL pro. And if we refresh this one here, you'll notice that we now have a listing as table exactly as we wanted it to be created. So now, quickly before I move on, I want you to kind of discuss something here which is inside of Docker compose. We have listing service or listing service DB. I use this service and it uses service dv. So now one thing to note about microservices in general is that the reason that you use Microsoft this is, is to get around the issue of load balancing. So basically when you have all of your code inside of a single service or a single server. And there may be certain endpoints which are used quite more often than others. For example, let's just say with Netflix, you'll find more often going to be streaming video, then you are going to be paying for a subscription plan or something like that. So in other words, Netflix, it needs a much higher bandwidth for its video streaming, then for its subscription service, or in other words, signing up or payment or whatever. So what that means is that if it has all of the inside of a single process, we'd have to double that process, triple that, two suits, whatever's being used the most. And that is actually really inefficient in terms of resource. So what Netflix actually does as a famous example of microservices is that splits it up into these so-called microservices, which essentially run independently of each other. And then when you need dancer to be kind of sent between different microservices, they all kind of communicate that way. So what we're doing here is in our case, it's a lot simpler than what Netflix does obviously. But we have two databases here are one to slow the listings. So the users here, and we also have two services. So we have a listing service and a user service hours and times. A microservices is a very small set up heat, and it's also incredibly simple because we only have one instance of listing service running, one instance of user service, one instance of each database. And what that means is that it keeps all of it relatively minimal. However, in a thing like Netflix, you might have, say, for example, a 100 instances of streaming services up at the same time, if not more. So, they need to have that in order to handle the amount of bandwidth that they serve a consistently. So then they have to deal with issues surrounding concurrency, that had to deal with issues surrounding a database reads and writes. They have to deal with things like eventual consistency. They had to do with a whole lot of stuff including like fault tolerance and all that kinda stuff. All of that is incredibly important, but it's not in the scope of this video. And the reason I chose not to cover it is because it's not strictly necessary to an understanding of microservices as a concept and to showcasing your ability to use it. It's also incredibly hard for me to kind of show you how that works within any given context. Because the way Netflix does it is incredibly different to the way some other company would do it. And also it's just incredibly powered by and the needs of the business. So this is not something that you can kind of cover all in a single video. However, there are great resources out there which kind of explain all of these concepts in a lot more detail in terms of So like blue-green deployments, like obviously continuous integration and how to deploy, how to make full you maintain a time between services, all that kinda stuff. So that's definitely worth having a look at in addition to the content within this video. But yeah, anyway, let's move on. So we've got uses service over here and we're going to essentially do something very similar for this. So let's grab a SQL eyes OSCE and let's put it down here as well. So we have that file there and we have a SQL eyes directory that we're going to paste over as well. So we have synchronized RC and we have a SCL lines. We're also going to go into uses. So this game, and we're going to add it in, yon, add MySQL to SQL, SQL CLI. So basically the same dependencies as what we just did, what it's going to add them back in here as well. So these 22, you can think of them as two completely separate services. As such, you won't have any kinda like dependencies automatically being stored for both. You have to consider them as separate rather than the same thing. Which is also why they both have separate databases. Because if at the end of the day they have one database, then you're not really getting around the issue that microservices exists to try and solve, which is that I usually they'll database is the one that suffers the most in the circumstances. So it's usually the one to kind of break the most often under pressure. So that's the thing that we have to kind of try and optimize here. So that's why we use three devices on, and that's what we're doing here. So anyways, we have our dependencies installed. Let's go inside package JSON and caught the other these two scripts here as well. So we're going to need those. We've got synchronized migrations and we have this one here. Let's actually just modify that. So the current time is 12221515, and this one is just going to be over nine. So once again, 201912, December 22nd, 3pm, 03:15 PM, nine seconds. So this one is going to be create and we're going to create users dot js like that. And inside of here, instead of listings, we're obviously going to write uses. We have ID out he allow null is false and then also incremental gonna get rid of this, keep primary key is true, but we're going to change the data types to UUID. So we're going to use you IDs for the users. It's just generally a security thing. I guess the best argument is that when you use the natural numbers like 12345, you can kind of tell how many uses their all and whether they were used as before, often, something like that. So it's just generally not a great idea, but really it doesn't matter too much, but that's what I'm gonna do here. We're just going to use e-mail and we're going to make this one a unique. So basically you can only have one email address, so you can't reuse an email. And this one here is going to be possible and hash allow null is false and data types dot char 64. So this is a big crypts hash which we're going to be using lifo. We're gonna show you how to set that up. We have created_at, updated_at and deletes for that as well as everything else here is the same. We have users and let's add one more here to 0, 19 1222151633. And this one's going to be creates user sessions dot js. So this is a second file and it goes underneath the first one because of the timestamp. And inside of here we're just going to call P, this one, paste it over here, change this one here. It's a useless sessions. And then we have an ID allowing all false primary key true. We're going to keep the UUID here for the session as well. Definitely a good idea for a session. And we're going to have use the ID allow null is false. And this one's going to reference the ID column inside of use this table. And we're going to write type is also a type style UUID. So when you reference another column in a foreign key like this, it has to match exactly. For example, allowing all false data types UUID has to match, allow no false datatypes. Uuid, you don't want to write primary Kate, you just want to match whether or not it's null and also the type. So those are the two I'm watching here. And then underneath here we're going to do expires at allowing all is going to be false. And type is datatypes thought Date. And we're also going to do create that, created that allow null false datatypes, thought data like that. So now that we have these three, we don't need to update to that and we don't need to leave that there. So we can say that like this. Now we have module exports op in both. I actually forgot to include the down. So the down is going to be module exports lockdown is equal to query interface like that. And then query interface dot drop table. And we're going to write user sessions like so. And actually this one's getting kind of stuffy. So let me do this. We have module exports down, query interface dot drop table like that. And we're going to write the same line inside of the other file. This one, he is going to be used as my bad uses to match uses and use the sessions to match user sessions here. So now that we have these two, let's go back into our big terminal window. Let's control D to exit that. And let's this time flows through dolphin ps. So have a look and we have, this one is CB. So we can just even try say honestly, because of the first cartoon is uniquely see out of these full. So that should lead us in. And then we can do beyond db migrate. And this would create two tables for us inside of there. So now we have uses and use the sessions about. You'll notice that they don't actually appear inside the same one for listings because the one for listings is obviously a different database. So now it's got a new tab again. And this time let's choose uses service TB, click connect, and now choose DB. And you'll notice that we have users and we have used the sessions. 4. Setting Up The GraphQL Server: So now let's have a look at going back into Visual Studio code here. Let's start building out the actual listing service so that we can actually access some information from here instead of that just showing working. So we're gonna do is just go into listing service over here. And we're just going to add in here yon express, cause and also body puzzle. So these are the dependencies that we need to use in order to get expressed setup. And inside of index.js here, we're just going to add in input at Babele forward slash poly fill. And let's also add an import hash route for such DB for such connection will create this in just a second. And also a force lifesaver for sludge starts server. So now let's add in these two files. Firstly, right-click new phi o dB for slash connects m dot js like that. And inside of this file here we're going to write import SQL eyes from SQL, like so. And now we're going to include important access m, which obviously we haven't created yes, helpers and then access and like that. And we're going to do DB URI is equal to access em TV URI like that. Constants equalize because equal to new SQL lives BB URI, and we're going to put a comma curly brace, dialect options. Chocolate is UTF-8 and multiple statements is true. For a comma and then logging is going to be false. Semicolon here, export, default, see collides like that. So now that we've got that, we obviously don't have this file here. So we're going to right-click New File helpers for slash access m dot js. And inside of this file here, I'm just going to call this method which I always use, and I'm going to keep using it. This one right here. So basically it accesses a variable inside a process dollar ENV, and if there is an error, if it can't be found, and this one always runs in advance. And the reason for that is because getting things from process I'll m is actually not that trivial a process. Usually you might just think of it as a regular object, but actually it does have some sort of like performance, a degradation. So it's not as performant as just simply accessing from an object, which is why we try to Kashmir which tends to speed things up. So now we have access m over here like this. Let's just get rid of this file cave close that. Now this one is working just fine, but we still need to create stellar forward slash star, etcetera. So we right-click you fall and serve a slash server.js like patch. And now inside of this foreign key, this one shouldn't firstly be working. So if we just go into here and we just save again, it should restart and should be working fine. Yep, no output means it's working just fine. And inside of this phone here we're going to write imports, body pause off from a body positive like fats. And then import caused from cause, imports express, from express, import access n, the same one as last time. Access m from the hash route for such helpers, slash access end. And then we're going to write console port is equal to access port like that. And the default port we're going to use is 7100. So if you remember what I said before, our services are going to be running on 71 zeros or something. So that's 17100 and then uses service will be 7101. So we have those two that I like that. And then we do constant is equal to express and then app.use. And we're going to add in the body parser middleware. And then app.use. And then for close here we're going to add in the origin, origin and cb, cb null, true. Credentials is true. And we're going to write app.all listen port. And then we're going to write 000 like that so it's exposed to the outside world. I'm not actually sure if you need to do that, but I always get into a habit of doing it and it's been working fine for me, so I just keep using it. And then this is our callback function when it works properly. So we're going to do console dot info and we're going to write listings, service listening on. And then we're going to put the port inside like that. So now we're restarting here and a short, short listing service listening on 7100. So now that that's working, let's actually draw it back into docker-compose here. And what we're going to do is for the listing service, let's add an poets here as well. Sorry, here for the pullets are brought you to pose like that. And we're going to just write seven, 1-0-0, seven 1-0-0. So what this means is that the internal port, I'm 71 zeros. All right, this is internal, which is represented here, is going to be mirrored or mapped to the outside Port, which is on my computer of seven, 1-0-0. So basically this allows me to access the listing service on this port number here. So let's grab that, let's copy that, go into use this service and basically add the same thing, except this one's going to be 7101 like that. So now that we have these two, let's control C this way for them to be killed and go back up here and we're going to start it one more time. Great. So now it is started. It does seem to be giving me an error here. And I'll show why I think this one is meant to be body posit JSON like that, and that should get rid of the arrow. So H, OK, so now if we go into goo, goo primarily K And we do localhost seven, 1-0-0. You'll see that we get this which says cannot get forward slash. And that's technically the correct message here because we haven't set up any routes for this one. So now that we've got this here, let's kind of grabbed the same thing and put it into Uses service here. So we've got SLC, we've got DB connection. So we can just kind of paste that over here. This one uses DVR IE as well. So this Fall studies all the same. We need to copy over the helpers directory as well because this one contains access nth. And then for the server, we can copy that one over here as well. Just a little change here, which this one needs to be 7101, and this one should be the user's service, service not services. And same thing here is that this one's services not services, listening on that port number. So now that we have that one setup here inside of index.js, we're just going to copy this one and paste that there. So the industry ice is the same and now use the service is restarting. We get errors because we haven't installed the dependencies. So now we've dot-dot slash key and we'd go into Uses service and we yawn, add body positive holes and express. So it's going to add those way for that to install. And now that that is done, let's save this one again and it should restart and a should be working just fine. And now that it's up, let's try go to 7101 and we should also get kennel get forward slash. So if both of those give you kinda get forward slash, then that works just fine. So now let's actually look at setting up some routes for our listings service. So what we're going to do here is create a file inside of here, and we're going to call this one routes.js. So this one's going to store all of our routes. And the format is going to be a set-up routes function. And it's going to take in the Express app like that. And we're going to do is exploit the default setup routes like sir. And inside of here we're going to do is import the setup routes from dot slash rails. Like that. And then underneath our middleware. So this is essentially our middleware section. We're going to write setup routes for the app. And inside of this file here, let's start adding in some code in order to handle the routes. So let's go in here and let's write app.get forward slash listings. So I folded listings. We're going to do flush right request Raz and then next. And let's just firstly simply do res.json. Let's just do a message. And this one is, say, equal. And we're going to just return because it's the last thing we do here. So I guess it makes more sense to return, although you don't have to. If you just do res.json, that works fine as well. But I'd just like to do that so that the function kind of stops running the, it's more of a semantic thing in this case. So now that we've done that, let's go back to seven. 1-0-0 should still get this era. But now if I go through forward slash listings, you'll see that I get message equals. So that's the right thing key to show on the page. But now that's not very useful to us because we actually want to see the listings inside of the database. So what we do here is inside of DB, let's create a new file and correspond module.js. And inside of this file here let's just write input datatypes and model from SQL eyes. And let's import SQL lies from the connection. So that's this connection file here. And then we're going to write this thing, extends model. And then listing dot in it. And we're going to put curly braces. Title allow null is false. And then type is not a type style string. And then comma description. And so it's going to be allowing all faults as well. And type is going to be dots as pipes, dot text. So now these two, He actually come from the SQL eyes directory. So they match up very nicely with this one here. You see that if we just literally copy and paste it here, there's absolutely no difference whatsoever. And the reason we don't copy over the other ones is because ID is automatically defined to that as well in any case. And then these ones are enabled by default. So we don't actually need to worry about those. So now that we've got this key, we bought that, put a comma cutting rates again. And then let's just include SQL allies and also doing modal name is equal to listings. So that's the name of Al model. In other words, Alice table and SQL eyes is l connection, so it knows how to associate this. So now that we have a listing setup IV inside of routes IB here, let's go up here and write import. And we're going to import this listing. So there's one key, we're going to import this thing from hashed route. Dd models like that. We're going to make this one async, which is why we included the Babel poly fill earlier on and went inside of here. We're going to write once listings is equal to a white listing dot find old. So we're going to get all of them and we're just going to return them inside of JSON. So return res.json listings. So now that we have that, we're going to wait for it to just restart and refresh this and we should get an empty array like that. If we were to go into SQL eyes every key, I'll start SQL pro. And inside of listings here, if we add in a new one, let's just say number one. And this one is going to be a cowboy hat. And the description is, let's say the hall. Created_at is now an updated that is now with these round brackets after it press enter, it should create it. And then if I refresh over here, you'll notice that we get that. So I'm going to very quickly install a JSON format cells. So this looks a little bit vessel. So now I've got that installed, let's refresh and we get this really nice layout just looks a little bit better. And you can see the role and also positive. So this is this one here. We kind of get all of that data inside of seven, 1-0-0. However, this data is only in our listing service. So technically our listing service, if you sold the diagram before and I'm going to put that back up on the screen, is that is actually technically private. So what that means is that you're not meant to be able to access this directly from the front-end. You're meant to access this through the API gateway. So we're going to have this onto here, and now we're going to start working on ala API gateway. So let's go back into Visual Studio code over here, and I'm going to show you how to get that set up. So let's just close those two here. And a four are currently empty API Gateway. Let's just create a new file. So Yana in hyphen y, and we have our package JSON API gateway. That's all fine. And let's add in here in terms of dependencies. Firstly, let's add in Babel watch as a depth dependency. So hyphen capital D. And let's do yon add double forward slash coal, poly fill, preset n. So these three key, and we're also going to add in a whole bunch of stuff in order to get graph QL setup. So we're actually going to use graph QL inside of the API Gateway. And I'm gonna show you why that's a good idea in just a second. But we do this and then we do a pop, Apollo Silva and then Apollo each cell by Express as well. And then also the Babel plug-in module result, which we made full resolving modules. This one's really nice. I use this one a lot. We're going to include a couple for expresses. Well, so kooky POSIX quotas express and then press Enter. So now we have all of these that we're going to include. The first few are awful babble. So these awful babble heat Apollo service for graph Q0, as is this one. This one's a Babel plug-in again, and these ones are for express. So we have all of those installed. And now we're going to right-click create a new file called this one. Felt would all config ab.js. And this fall is going to be exactly the same as this one here. So just grab that and copy paste it here. It's the exact same thing because we're kind of having that same layout, which is not necessarily a bad thing. If it works well, there's really no reason to change it. So we want to close this funky right-click new file and we're going to create one Dockerfile heat. And this Docker file is going to be exactly the same as all of the other ones because it's also a NodeJS process. That's essentially what we're doing just getting Version 12 called the FTIR Run. Cmd sold the same stuff inside of package JSON here. I'm going to include scripts and then watched as well. And this one's going to do babble hyphen wash, capital L like that in a flag and then SRC forward slash index.js. So now that we've got that, let's right-click here new file, SLC four slash index.js. If I can spell that correctly. And we're going to just do console.log working like sudden quick install that. So now if I save this and we go over into docker-compose, let's actually add in API gateway. So we're going to copy this. Put it right at the top because alphabetic order is nice. We're going to do that and we're going to do API Gateway for both the name and the build directory. However, we do not need the environment. And for depends on. We're actually going to depend upon listings service and also uses service because these two are the ones that are really important to get working here in order to get the API Gateway up. So now for the poets, we do 7 thousand instead of seven, 1-0-0 and fully volumes, we're going to use API gateway here. So now let's save that Gary V, K Control C. And this time instead of building directly from API Gateway First, let's just do docker compose up, and it will automatically do that for us. So now let's draw up here, press up and then docker-compose up again. And now it shouldn't have those. And we're also starting API gateway. So API Gateway, he just pay attention to the red. It should come up with working at some point. So she was working here, which is pretty cool. So that's a good thing. And then now instead of obviously just showing whacking, let's start building this one out as well. So this one's kind of similar to the other ones just at babble flow slash poly fill. Important hash route forward slash, forward slash sought sub off. We don't have a database for our API gateway, so we don't need to include that database stuff. We right-click New File Server, forward slash stats server.js. And for this font here we're going to do import Apollo server from a Paulo Silva express. What you do import cookie POSIX, which we'll use later on as well from hyphen cookie pauses like so, import cause from cause and then import express from expressed like that. So now that we have these ones, that's also include access f, the input axis m from helpers, access em like so. And we can just grab that, grab helpers, paste it in. You do realize that I am using access emf across three different places. And the reason I choose not to kind of put it out in a shared modulus. Something is because I feel like at this case it is more the exception than the usual. So it's light. It's not something that needs to be a modularized. And you really can't assume necessarily about the methods of accessing environment variables and configuration is going to stay the same from project to project. So I just feel like it's probably better to keep it individualized for each of them as opposed to kind of putting them all in the same place. So we have that and we do coins port is equal to access. Port is going to be 7 thousand. And let's create an Apollo seven. So before we create the Apollo several, lets have a look at this error on the side. So we can't find a service thoughts Sabha, which we do now, but that's fine. What we're going to do is we're going to right-click key a new file. And let's create graph Q0 forward slash type depths ab.js. So this is ala type definitions file, and this is what we write inside a key. Input G cute l from Apollo settle. And then const type depths is equal to g, q, o like that. And inside of here we are going to include a single type first. Listing is going to take in description like that, and then also IND and also the title. So if you have a quick look over here at the Dasa that we had from our listing service. You'll notice that we have ID, title, and description. You'll notice I'm not actually parsing it and create to that and update to that. And the reason for that is, well, there really isn't a huge reason as to why I excluded it specifically or something. I just feel like at this stage I'm not really making great use of it anyways. So for now I feel like this is just fine. So we're going to do batch with ID, title and description in listing, and we're going to do type queries. So we're going to set up our query key. And now query's going to be listings. And listings is going to show an array of non nulla listings. A non null array of non null listings. So that's kind of complicated. But anyways, now let's do export default type depths like fast, and just save this one here. So we've got our listings, This thing like that. And now let's set up a result. Lots are actually resolve these listings. So in order to do that, let's go into graph Q0, Q0, right-click New File. Resolve is forward slash index.js like that. And then inside of here we're going to do import all as query from dot slash query, which we obviously haven't written yet. And then cleansed result is, is equal to and then literally just write curly braces query inside like that and then exploit defaults result is. And let's do new file query forward slash index.js. So we have index.js k, but we also should include listings. So let's just write in here export default as listings from dot slash listings. And then for this one here we are going to save, we're going to right-click query New File listings, ab.js. And inside of this file here, we're going to write in constant listings resolve a is equal to async. And let's just return on a set of mock data. So its square brackets for an array and then curly braces id say one, title is test and description is a boo. Ya, let's just do alphabetical order. That's endless. Do, exploit, default listings resolve, I like so. And now let's hook this up with allograft. Ever since either serve as thought server key. So Leslie, we're going to write here Import result is from hashed root graft QL result is. And then we're going to duplicate that and do typedef as well. Let's just make sure that our result is actually being exported. Yep, that's fine. And then what we're gonna do, a Polish sub o is equal to new Apollo seven like that. The context we're going to write this and I'm gonna explain what it does laser on resolvers and typed apps. Actually, let's get rid of this now and I'm going to add it in later. So then we're gonna do one-stop is equal to express app.use cookie pauses. So this allows us to read cookies later on app.use and we're gonna do colas. This one's going to be very similar to the other ones. So let's just copy that. So selfless thoughts and grab the exact same thing inside a cane. And now let's do a polar sub to apply middleware. And then app a clause is false because we already specified cause options he, and then the path is going to be forward slash graph QL salad. So save that real quick idea. Minimize this so we can see a properly. And then let's do app.all listen. And then just 0000 like that. And then something like this console dot info. And this one's going to be API Gateway listening on and then the port number. So default port is 7 thousand, which we're going to use heat. So now that we've got this, oh, let's open this up on the site again. Index and save this file here one more time. Say if that's and it should restart and hopefully should be working just fine. So if we do restarting, yep, it's on 70 thousand. So let's try to go to 7 thousand. We get this error, which is good. You go to Graph Q_l and we get the graph QL playground. Let's make that a little bit smaller, and let's try curly braces, listings. Let's do a description, ID and also title. And let's press play and we get our test that Bu Yao. So that's really cool. So that part is working just fine. However, this is our MOOC data and it doesn't actually get data from ala listing service. So that's something that we're going to implement now. 5. Setting Up A Mutation For Creating Users: And now let's hook this up. We've got this thing here, but let's go back into our result. So inside of listings here we have our listings resolvable. And now we'll go into connect this into ala listing service over here. And the way we're going to do that is with an a ductile. So for our data, let's go into SLC and let's create adaptive. And we're going to call this one listings services.js. And what I mean by adopted is basically a file with a kind of acts as an in-between, between your API Gateway and the actual listing service itself. So we have this file here and we're going to include imports brought from God. So we're going to use, we're going to add that creates a yon added got. Got is basically a Request library. It's kind of like ICR's, but I wanted to try something different here. And it turns out it is pretty darn good. So we're going to use that. We're going to do ponce listing service URI is equal to and then HTTP. And remember what I said before about Docker BAM to substitute the name is we can just write listing service colon 7100. So that looks really cool. In order to get this one here, notice the port number here as well. We're going to do that. And then we're gonna do export default class listing service. And inside of here we're going to include some static methods. So the one we're going to use is static async, fetch all listings. And we're actually going to basically ping this route here. So in order to do that, let's do cleanse the body is able to await and then put back ticks and the listing service URI and then forward slash listings. And this one's going to be a dot JSON and bn. So we return a JSON data and then we do return body. So this one will basically get that body and then return it for us. So now inside of listings here we're going to import this file. So import listings service from hashed route for slash Classes listing service line. That's going to grab this and we're going to return a white listing service got fetch all listings. No suggestions is fine. Let's just do that. So now that we've got that, you'll see that it's restarting over here. It does seem that we have gotten an error. So classes at this one should be adopted. That's totally my bad. And now that it is running properly, let's go back here and let's press play again. So now you see we actually get yay, whoa, and cowboy hat. So you notice that from our API gateway, which is localhost 7 thousand, we were able to access the docx file from our actual listing service DB via the listings service. So it's kinda like, you can think of it as like your API Gateway being almost a middleman type client because it actually sends HTTP rest requests to other microservices inside of your system. So it's actually really nice, I can do that. So now that we have the ability to fetch listing things that's already built out. That's really cool. And now let's also have a look at being able to work more intimately with users. Honestly, it's a very similar thing. If we go into user service here, go to SRC and go to Silva. And we've gotta start sever. Let's just create a new file here. I'm gonna call this one routes.js. And inside of this file gate, we're going to write a setup routers equal to app like so, and then export the default setup routes, the sulci. And inside there, we're going to import that the input set up routes from Del slash routes. And then this one we're going to do underneath L microbes, underneath our middleware, setup routes like that. So I want to pass in the app and we've got our app here. So now first one I'm going to do is basically one that allows us to create new users. So inside of here, let's just do an app dot post forward slash users. So we need to oppose request in involves creating something. So when we do app.all post for SAS uses, we're saying, hey, let's have a look at creating users now. So that's what we're doing here. We've got four slash users and then we're going to do Async request response and then the next like so. And we're going to do a quick check. So if the email isn't found, all the password isn't. We're going to do basically pass on an era. So return next new errata. And we're going to do in valid buddy. So it's going to possibly era along. And what I'm gonna do here is put a try statement. And then we're gonna do a const. And actually before we do that, I totally forgot to add in the model for the user. So inside a dB here, let's create a new file called this one on models dot js. And inside of this molecule is through an import thought of types of models from synchronized. And then import SQL lies from the flush connection. Again. Let's do export class USA extends model like so, and then user.name knits. And inside of here with your curly braces and go into SQL migrations of asphalt, he got ID, email, password, hash. We don't need to provide these ones, like I said, because it automatically knows how to initialize those. So we have these three heat. The reason we're including ID this time is because LID is actually custom. Notice we use a UUID. This one's slightly different, so the default one. So that's why we're including a heap curly braces here. And we're going to do default scope. And then we're going to actually exclude a password hash from the default scope. So the reason for that is because obviously the password hash is quite confidential in times of inflammation. It's not the kinda thing you want to be passing around all the time. So that's why we exclude it from here by default. So we do that, we do comma and then model name is going to be a uses and want to pass in the SQL eyes here like that. So we have this one and we'll also have export class user session with two S's that extends model. And we're going to do user session dot init. And then are basically very similar thing, very here, grab IT US, IT expires apps. We don't need to grab create to that because that's built in. We don't need to write this a references section here, although we can keep it, I guess it doesn't really hooks. And then we go here after this one, port comma 20 braces and this one slightly different. So we have our model name which is a user sessions. I'm paranoid is going to be false. So paranoid basically gets rid of the deleted that one. Notice how we don't have deleted out here. So if it gets deleted, it actually gets like permanently delete it. So that's what we're going for here. And we also don't have aphasia. Something is false because we're not really looking at updating a session. So now that we have used a session, he usually he. And then what we're gonna do is go back into our routes here. Go to the very top, and we're going to do import calibrates user from hash DB models like that. And then inside of our try statement, we're gonna do const new youth size equal to a white user dot create. And we're going to do email is going to be requests, I'll buddy dot HTML. So we pass the email in. And then for the ID we're gonna do generate UUID. We're going to create this in a second. And then for the plasma hash, and we're gonna do hash password request, I'll buddy the password. We're also going to create that in just a second. So now if we generate UUID, we do import generated IID from hash route helpers and then generate UUID nouns. Grab this. Copy that, go into helpers here, right-click a new file, paste this dot js like that. So now we're going to go here inside a terminal, go to User Service, and we actually need to yawn ad do UID. Id is the one we're going to be using for the solid here. And this file is really quite simple. So import UUID V4 from UUID for slash before and then generate the id function literally is just going to run this function and then return the value export default, generate UUID. So we have this file here and we also need hash password. So new file, hash password ab.js, and this law makes use I'll be crypt JS. So once again, yon add the crypt JS here. And inside of hash password we're going to include this first. Include decrypt js and then cons hash password is equal to password and then decrypt dot-com hash sync, not comparison, sorry. And then possibly had the script.js salt to sink, and this one's going to be 12. So basically this hashes ala possible using the decrypts algorithm, a total of 12 times. So the more that you hash it, kind of the longer that it actually takes to hash, which makes it a lot harder to break. For example, hashing in 12 times or takes toll times longer than hashing at a single time. Which means that if you're cracking the password and you work going into previously done it a billion times, which might take, for example, say one or two days to crack. Now it's 12 times longer, which means it's going to take 12 to 24 days. But usually if you actually cracking a postulate of this length, it's usually going to take in the billions of years already. So I'm multiplying that by 12 basically means it's practically unsolvable. So that's what we're going to use here for the hashing. Hash password is like that. And we're going to include that inside of here as well. So now we have generated UUID and we have hashed password. And what we're gonna do is just return here res.json are with the new user and then we're gonna catch an error. And if we get an arrow, we're going to pass that on into next year. So now that we've got this, let's actually go back into start server. And at the very bottom here, I will underneath setup routes, we're gonna do app.use. And this one is a very special type of middleware. This one specifically is an error handling middleware. And I guess it's not really a middleware in the sense that actually goes off to everything else. So that's what we're doing here. And we're going to do return restless status 500s. So some sort of Silva era JSON like that. And we're going to take in a message which is going to be a red.me. So for example, inside of our routes here, when we do invalid body, this is the message inside of the era. So that's what's going to show here. So now that we've got this, what we're gonna do is just have a look inside here, make sure that uses service is accessible on 71 or one. And now let's go into postmen. So I've got postman or my computer. You can download and install postmen for free as well. And this is what postmen should kind of look like for you. Let's create a new request here. And we're going to change this one to post because it's quite difficult to kind of orchestrate a post request within your browser. Forget you can literally just go to the URL, but for posts, obviously, it's not that simple. So we're gonna go, he understood HTTP localhost 7101, which is ala, uses service and we're going to post to users. So now this one here, as you'll see, it expects if we go into rounds here, an email and a password. But we're actually going to just firstly start off by passing in nothing. So algae's aren't going to be empty and press send and we should get back an error message perfect saying invalid body. So now let's try adding an improperly for ones. So what role here I've chosen JSON and we're going to write an email and let's do test1 at example.com. See if I make this face gray. And then we're going to go here, but a comma and the right password, and let's just write password for the password. So now that we've got this, let's click send. And let's go down to the bottom. And you'll notice that we have a new one created for some reason, the password hashes in there as well. I guess that's not too big of an issue at this moment and I'll explain why in just a second. So now we've noticed that we have one user and that matches exactly what was created just here. Now if we actually tried to create another one with the same email, we should get an error. So we get a validation error here. And the reason is because our email is repeated. So this validation error comes from SQL eyes, which says that you're breaking our unique validation constraint, which is that you can't have the same email address twice, because we wrote that inside of this file here. So unique is true. And then started models also unique as true here as well. So that's why we're getting about era, but that's working just fine. So now the reason that it's okay for us to show a password here when we're creating for the first time is because like I said, the user doesn't actually have access to this route they use are only has access through this, through the API Gateway, which is something we're going to be enabled. And now if we go into typedef, so here, let's add an alpha as mutation. Type is going to be mutation. And this one's going to be created user. And it's going to take an email which is a string, and then also a password which is a string. Now notice how the ABL and Tolkien and email and password, and we're doing the same thing here. So we kind of have to have that same similarity across our code base because we're passing through so many different components. Yes, different modules, different services, whatever you wanna call it, that is something which you would tend to have to do with microservices is how geodata kind of pass through quite a few different stages. Let's do type use the heat. It's going to take in an email and it's also going to have an ID. Like I said, we're not exposing anything else yet. And this is something that's really great about graph QL is that you can specify exactly what the author that user can see. For example, if we don't write password hash into here, there's no way that the user can actually access the password hash. So we specifically specify the properties that'll be passthrough. So we only allow them to see email id, which is great. So that's working just fine. We have our mutation and we're going to add that into our result is here. So new file mutation for slash index.js. And this one's going to do an export default As. And we're going to do a create USA which matches this name here. And inside of index we're going to include a mutation like that, mutation like that. And inside here, right click New File create users.js. And inside of this hall here we're going to write clumps to create user resolver is equal to adolescents right out a basic function export default create views are resolved if I can spell correctly, and then put that day like manifest. And now inside of here we're going to first to make this async, and then we're gonna do OBJ, which we're not going to use, and then curly braces, email and password. So the second parameter is the set of arguments being passed in. And in our case here we expect an email and password and we don't really need to do too much validation on that because we already said that they have to be strings and that they are required. If you want to do additional validation, you can. But for the sake of this project, I'm keeping things quiet, minimal and quite simple. So I'm making a lot of assumptions here. So now let's go into adaptors and let's create a new file. And we're going to call this one a uses service. So surprise, surprise. This one's going to be interacting with the user service. So now this one here, we're going to call it a user service like that. This is going to be uses the service URI. This was going to be 7101. This one's going to be uses, I guess, and sit out instead of this we're going to write create USA. And this one's going to take in email and a password inside of an object. So the reason that we pass it in inside of an object is because if we just do single premises like saying e-mail, like say for example, an email from impossible like that. The reason that that's bad is because then what if we had to add in something else, then it has to go into the end. And what if we have, say, six or seven different parameters, then you don't know which one comes first, don't know how to put them in properly. So using an object is almost always a better situation when you want to have names, parameters being passed into your function. So we have this here. And let's do body equals await, gots dot posts, and then uses service API and then forward slash users. And we got two curly braces, JSON like that. And we're going to pass in the email and the password, as you may understand. And then we're going to do dot JSON to return the data in JSON format and then return body like that. So now we have this one here which uses user service API and our URI there. So this one should probably be API, API should match. Alright, URI, I didn't write your eye here. So this one should be URI. For consistency's sake. That should be like that for such uses, JSON or that kind of stuff for ten buddy, right? So now that we have this method inside a crate, usually here, let's grab that data import uses service from hash route slash. Adaptive slash uses service like fat. And inside here we're going to write return a white uses servers thoughts, create, user. And then we're going to write email and password like so. So we're gonna pass those in and hopefully this should be working just fine. So now that we have this, we're going to wait for that to restart real quick. And now that that's where he started, let's go back into Google Chrome and let's refresh real quick and let's get rid of this and write a mutation. So mutation we're going to do a create user. I'm passing an email test2 at example.com. And the possible it's going to also be password and then ID and also the email. So now we've got just kind of doing this inside of the graph q o playground for now, obviously later on we're going to integrate this into our app. We're gonna keep this for now. So we press play and usher run and it should create a user for us. And I think it's now if we refresh here we have tests to now what happens if we press Play again? We get this kind of error. And it says response code 500 Internal Server Error. And it gives us all this kinda stuff, but we can actually handle this a lot more nicely. So in order to do that, let's go back into VS code here. Let's go into slots cell, but everything inside of Soviet here we're going to create new fall on the coldest one format graph QL errors. So we're going to create this fall and we're going to write here. Firstly, we want to add low dash. So you go to API Gateway, yon add low dash. And for this one here we're going to write import underscore from low dash format graph QL errors is equal to error. Error details is equal to underscore doc gets era and we're going to do original era dot response.body. So the reason that this works is basically inside of the graphic yo era. We have this property called original era. And original era contains the original era that was taken from say got o wherever the era came from, the graph TO kinda wraps it. So we take that original era and in the case of God, it actually has a dot response.body and dot response.body comes from the actual request itself. So for example, if your request comes back with a 500 error, it's going to era, but it's also going to pass the data like the curly braces and the message inside of response body. So this allows us to get that on the event that it exists. If it doesn't exist, then this would just give us undefined, which is also fine. So now we do a try block here. And if ever details exist, then we return JSON.parse era details. For some reason we don't get it as JSON, which is kind of disappointing, but that's fine. Just do that. And then catch a return null, export default, format, graphic IO errors. So if we can get the details, let me do this. Otherwise we just return and all for the ERA and there's not too much else we can do here. So we grab phonograph fuel areas and let's include again. So we have that. And then here we're going to do format error, format graphic your errors like so. So now that we've got that, if you see a restart and hopefully I should be working. Yep. Okay. Working just fine. And let's go out here and let's press play one more time. And you'll see that this time we get the validation error. And this time if we also like, for example, if we leave out possible we should get a graph cure all era. Or in this case here we just get errors is null. So we can actually see what the error is. That's the cause of graph QL. Basically, the evidence doesn't show anymore, for some reason, only could just return the original era. I guess that might be better here because if we can't get the error details, then we can return the original, which allows us to see the validation error. So let's wait for this to restart. And now let's get rid of them. Husband, press Play. And then we see that we need to provide the arguments, although Law and it keeps on going on. So anyways, so now it's giving us the errors properly, which is really cool. So this is kind of how you would do error handling. If it were a more professional projects. Kind of spanning a lot more stuff. You might have like, you know, different microservices, but you kind of want all the validation to be done in the Gateway or gateways depending on your setup. And this is probably like a very minimalistic version of how you would want to do that. 6. Authenticating Users Using GraphQL: Okay, so now let's continue and let's have a look at maybe building out a bit of the front end. So we have this one. He obviously is working and it's all fine, but we still have an empty classifieds app directory. So I'm thinking about this one here. We could just go into heat, go into the classifies app, and let's just do a yon in at hyphen y. Now let's open up package JSON IB here. And inside of this file here we're just going to add in a few packages. So yon ad and let's just do a hyphen D, possible Bundler like so. And we'll wait for that to install. So we're going to use possible for this project just because it makes things a little bit simpler. If this were production, I generally go with web pack. But as I said, like really it's just up to you and for the needs of your projects. I tend to find possible to make life a lot easier when I'm setting up for the first time. But if I'm doing something which is more, I guess technical and more like kind of customized, then I'd probably consider using web pack. So now inside of Classifies healer scarred, crania fall, as I'll see, index.html. And let's put in our basic HTML document like so. Let's get rid of this one and that one there. So we're gonna keep the character set. We can keep the language as well. And we're gonna call this one a classified ads up. And inside of the body here, let's just do divide equals. And then Script SRC is equal to dot slash index.js. So just like that. And then SRC, right-click New File, index.js. And let's just do a very, very simple reacts. Quote unquote up, sort of react on no reactor. And let's do a render H1 working document.getElementByID. And let's write off inside of here. So now that we've got that inside of classifieds up here, we're just going to add in a script. So Scripts and we're going to do watch. And then possible SLC four slash index.html. And the port number we're going to use is 7,001. So we're going to use 7,001 because essentially what I'm trying to do here is make all of the 7 thousand ports, the ones that are accessible by the user. And that's kind of like the informal thing of what I'm going for here. I'm just trying to be a little bit more organized when it comes to these things. But at the end of the day, it really doesn't matter too much. So now we have something like this. Let's go in here and my yon watch, and it should start running and then installing, react and react on because we are using them inside of here. So that's one of the great features of the puzzle, is that can actually install dependencies for you. So it's got to wait for that to finish. Okay, so now let's go and check out localhost 7,001. And you'll see that our page says working. So what we're actually going to do here is firstly, let's go inside us. I'll see open up index.js. Hey, oh, actually let's first started to package JSON and let's add in an alias. So for our alias here we're going to do a hash root once again. So we're sticking with that kind of same thing here, which we're going to use in order to get it working, we have to restart parcel, someone restart it like that. And right-click here, I'm going to create a new file and drag components roots, router, dot js like that. And I'm going to just create this component. So and then open this up, create new file index.js. Do that. So we have index.js, we have routes. And I'm going to run the other root component to import route from hash brute forward slash components for such a route like that. And I'm going to render it KD onto the page. So now that we've got that, let's just check, make sure it says root. Again, that's playing. And let's just add in a few basic styles using star components. So we're going to go out here and import creates global style from stalled components. And we're going to go here, constant psi is equal to create global style like that. And then we're going to do at import URL, and we're going to grab a Google Font. We're going to go to Google.com forward slash fonts and we're going to grab robot car. So to such 1P, right rubato, and then click plus, and they vary here. And we're going to customize and choose a four hundred and seven hundred. So we have L2 here, which I'm going to use for this project. You really can use whatever you want, but that's what I'm going to do, something like that. And then I'm going to do HTML, body app like so. And then run it through a pipe, a 100% margin and zero-padding. And then with a 107, these are some basic stopped I tend to like to do for the majority of my projects, we're gonna do a rubato sensor up here, down the mountain. And then let's go here. Let's do that. And let's do a whole level of styles. So we need to run the global style he onto the page and then end that one off like Sir. That's gonna wait for that. Okay, so that those random, but this one should be fixed, but it doesn't. So, I don't know why. Anyways, let's have a look now and you see that we have the robot here. Fun working on the page. So now that we have this, let's go back into root and inside a root here let's just create the basic styles for this page. So firstly, let's create a RAFA. So let's first import styled from cell components. And then let's do constant Rapa is equal to style dot div. And this one's just a div which kind of wraps around the whole thing. So we do a box-sizing, border-box. Let's give it a full height and a padding of one rent and a width of 100%. So downside of hey, we can just do say our wrap up. And let's just say hi. So now if we save that go here. It just says hi on the page. And if I zoom out, it's actually not big. So it's quite offended small. And inside of the rapidly here we're going to put a container and let's just write something inside the container. So fill the container. The styles are going to be a silo dot div like that. And then we're going to do a display flex like slow rondo wrap. Lets the margin 0 auto and the width is going to be 80 Rehm. So it's a refresh over here. You'll see that it's now in the middle like that. We have container and inside a container we're going to have two things, which is by reused display flex here. So the first one's going to be the content. What HDF in there and our content is going to fare heat. Content is equal to style doc did. Let's do something like that. And it's through flex one module, right? One rim. And let's add in a sidebar. So sidebar the heat, this right, something else inside of there so we can tell what's going on. Cyber is equal to style dot div flexes 0 also, and width is going to be ten Ren. So now that we have that, let's go back here. You'll see that we have this one over here on the side and this one over here. So if we right-click, we'll actually if we go here and give the side boss and color and also give the contents and color. It's a great way to see how much we're going to actually type up. So this is the sidebar, this is the content, and this is a page. So now let's actually get rid of both of base. So that's endless. Get rid of that. And now let's just keep this basic layout. But first, let's have a look at maybe thinking about what we're going to implement next. So inside of uses service here you'll notice that inside of a subway routes over here we have a route for adding a new user, but we don't actually have a way to sign in. So I think maybe now it's a good time to add in the sign-in routes. And then once we do that, we can add be accompany functionality into the API Gateway and also into the front end classifieds app. So what we're gonna do now is add it into k. So to do this one, let's go out here and let's add an app. And we're going to add a fourth such sessions. So basically the idea here is that we're going to use dot post on forward slash assessments. Now you might be wondering why we don't use like dot post forward slash login. Because technically inside of rest, what you wanna do is rest is resource-based. So for example, when you do post twofold slash users, you're creating a new user. Now when we do post 3 fourth slash sessions or creating new session, which is the concept of a login. So that's what we're gonna do here. And let's do Async request response and next, like this. And basically the same check here. So if we don't have an email or a possible and we're going to do that. And what we're gonna do now is I will go into effect for the try block. So try like that and catch E open and just fix this catch a and we're going to do return next E. So we're going to pass the era along. And inside of here we're going to first set the user, so user as you can to await, use it or find one. And this one we're going to do firstly, attributes is going to be this. So if you remember from before, in aside of models here, for the user, we actually do exclude password hash. So what this will do is this will get rid of password hash from the model because of basic security reasons. Now in this case here we actually do want to include it. So we're going to just basically nullify all those kind of hidden attributes and put it back in. And then we're going to do well. And then email. And for the email wanna do wreck dot-dot-dot email like that curly brace, curly brace and then round bracket at the end, like so. So now that we've got this, we've got the user. And if the user isn't defined them, we returned next new era and we do invalid email. So an invalid email has been given. And now we have this function here. So if not possible to compare, sing, request dot body the password, and then use an apostle and hash. So if this doesn't match them, we do return next new era, and now arrow will be incorrect password. So now before we continue, let's actually add in this file here. So alpha possibly compare sync. We're going to just copy that name, going to help us right-click New File and put in possible encompassing ab.js. So downside of this bulky larger input v crypt from the crypt AS like that, a cons password comparison equal to password through test password hash like that. And we're going to do decrypts.com sink and we're going to do password to test and then password hash. So this is another thing which the big crypt library can do. Not only can it hash your strings and your data, but you can also test it against a given hash. So this is what we have here, and then we do export default password capacity there as well. So now that we have this file here, let's make sure that it is being used. I spelled that wrong. So I was wondering why this was gray, but that's fine now. And inside of routes here, let's just go here. We've got returned next new era. And then underneath this section, we're going to do plus expires at, is able to add hours and you do that. So it's going to be based on a number of Alice from the current time. And it uses session expiry Alice. So this is just a are constant. And for the sake of this project, I'm just going to define it inside of this file here. But you can imagine that you'd add this somewhere else. So for now, let's just do a useless session. Expiry in terms of Alice is going to be one Ala. So now in order to get at Al was working, we actually have to go into our uses service. And let's do yon add dates F and S. So it's the actual date functions. And we're going to include Elvis, the input add hours from date F and S like that. And then we got at Alice here for expire as, as ponds session token is used to generate new ID. So we can use the same function which we've used before and we've already included. So that's pretty nice. And then we can do session is equal to a White's uses session dot create training session key. And it's going to do it as asked. And that ID is going to be session token and then use the ID is going to be usually dot id. So we basically pass in a whole bunch of stuff on the session token is the, is going to be the Heidi key expires. Ach is just the current time plus one alpha and then use ID is the ID from the user we selected. Do ethics on TV, and then we do return res.json useless sessions. So you've written the session as JSON Tosca. So now that we've got this, we can actually zoom this out, but it's just the format things a bit weird because of the size of my screen. But let's just keep it like this for now. And let's go back into postmen. And let's do likewise 7-1 or one session like that, sorry, sessions actually. So then here we've got a email and password. If I remember correctly, this email and password is valid. So let's first try one that's invalid. So let's spell password with an E and let's click send. And it should return positive. Possibly comparison because not defined, because I forgot to include it. If we just do positive, that will add it in. So now we save that weight four, okay, so we get incorrect password. And then if I changed as possible back to an O and I'll click send. And you'll see that when you use the session is not defined. Yet. Another era, this ad in user session via like son. And once you do that, if you click send one more time and we seem like we can't get a response. But then now you see we get expires at ID user ID and created that. So now we have a new session and this session will appear inside of users sessions. Now note the IDs FC7, FF, and that's the same ID here. So we just created a session, we essentially just logged in. So this is the functionality inside of a user's service. But now let's have a look at implementing this inside of the API Gateway. And we're going to show you what I'm gonna do inside of there. So now in the case of the API Gateway, I'll let's first go into graph kyeolre here, go into Type deaths and awful the mutation we're going to add in a new mutation. So this one's going to be create user session. So it kinda matches the same naming convention. We actually do use the same thing, so we can grab that. But this one cation say user session. Can we prove this on just a little bit echo. So now we have user session here. And let's add in this as a type. So type uses session. This one's going to take created_at, which is a date, expires out, which is also a date, the ID, and this one's also going to take a user. So I want to show you how to implement that as well. Now, appeal if through a scalar, right? So this date is a custom kinda type. And in our case here we just use Scalar to define that. So once you define a type of scalar, you can actually add additional configuration as to how that data should be displayed. But in our case here, we can just keep it as a scalar and I'll do anything much about it. Okay, so now that we have the scalar here on the page and we have a create user session. Let's go into resolvers, let's go into mutation, and let's create a new file, create user session like Sutter. Ok, so now inside this faulty, what we're gonna do is first go to create user. Let's basically copy the same thing over. And then for the create user session, we're going to tend to want to write this create user session here like that. Instead, we're going to create the session. So const user session is equal to user service dot create user session. And let's minimize that. So we have this here. And before we continue, let's actually add it into adaptors and our user service. So inside this file here, what it's going to go here and add in a static async create user session. And let's do email and password like that. The body is equal to await gots dot posts and then uses service API before with slash sessions. And then we're going to do curly brace JSON. And we're going to pass in the email and the password, and we're going to return the JSON data. And then let's do return body to get back the body. So we do create user session, sessions and we get a new session basically, and we pass it back. So now we have a new session inside of here. We need to do a white here for the session. And what we're actually going to do is we're actually going to add this in as a cookie. So in order to add it as a cookie, we have to essentially do response dot cookie and I'll use a session ID and so on. However, the problem is that inside of graph Q0, we don't directly have access to the response. But what we can actually do to get around this problem is inside of here, we need to go into Silva starts server.js. And here where we have the Apollo server, we just need to add into here contexts. And then a is two a. So for our context here, essentially, this defines how our graph QL, the third parameter, Biograph Girl, resolve is what? So the third parameter is the context. First one's the objects, the odds, and then contexts and an info. So the third one is contexts and this defines how it is sent. Now, I don't know what it is by default, but for some reason by default, it doesn't quite work properly. But when we do a, a like that and we just return it, just basically have a function that returns it as is. And we can actually access it. So we do that then. And then here we can do context as the third parameter there. And then we can do context dot, dot cookie and now actually give us access to that. So now that we have this often with double quotes here, we're going to do use this session to ID, and then we're going to set this cookie to be HTTP only to be true. So essentially just explained here, the name of the cookie is use a session ID. The value of the cookie is use the session dot id. So basically that's the ID of the user session or otherwise the session token. And then curly braces, HTTP only is true. So what this means is that some cookies can be accessed by your browser. So the JavaScript code running in your browser can access some cookies, however, other cookies copy access and those unknown as HTTP or only cookies. So the benefit of not allowing your browser to access it is that you actually haven't been more security because it is not kind of sent to all of the JavaScript code on the page. So this is really important to include. And now let's just do return user session. So we kind of split it out because we had to do this between this and that. I'll just put it in a variable and then just return it afterwards. So now that we have this curve here, we should be able to get create user session working. So now if we go back into Chrome over here, go to the playground, zoom this in just a tad, maybe a little bit more. And let's do a create user session, and let's do the ID like that. And we do a test one, example.com, and let's just do a quick refresh and then click play. And we get null for this, which is a bit weird, but let's see why. So I forgot to include it here. So we just need to include that mutation inside of index.js again. And now that we've done that, let's go back here. Let's click Play uses service APIs. I'll define a typed API again. I should've typed uses Service, uses service URI. So let's just fix that up real quick. I actually don't know where my thing on the side when. So that's kinda weird as well. But anyways, let's just click play on the time and we get a new session. So this 16912, and we have 6912 in here as well. So I'll create user session method is working. So now the API Gateway is kind of working in this regard as is the user service. And now we're going to hook both of these up to the classifieds app. Since IT here we have content and we have a sidebar. So now for the sidebar here, what we're going to do is add in a login component. So inside a root here, let's create a new file, and let's just do login, login dot js like that. 7. Fetching The User Session Using React: So every key inside of login, let's just first put in a very simple components. So we have login like that. So new file index.js as well. And then logging in here. So we have a index.js which includes login, and then routes which then includes login API inside the sidebar. And we're going to do just that. So we're gonna do that for login and then do locking down here. I see, I see I have logged in over here on the side. And if I zoom out again back to normal, so then it is over here. So that is where login will be. So if a login here where you are going to use a reactive form, the input use form from React hook form. And I've made videos on how to use form in the past as well. So you can go check those out if you feel like that's necessary. But what we're gonna do is just do cons. On-state is submitting handles submit and also register is equal to it. Use a form like that. So these are the ones where you're going to use and key we're gonna write a form on some it is equal to onsubmit and we'll define on summit right now. So let's just say put something there. And then let's go here and let's do onsubmit is able to handle summit. And let's just say we take in the email and the password, and then let's just do console log. Email password cipher works correctly, will have both of those onto the page. So now inside of here, let's first create a couple components. So firstly, the solid component is going to be a label is equal to style dots labeled like that. And then we're gonna do a display block. And then for those that aren't the first child, we're going to give it a margin top of 0.75 ramp. So now inside of here we're going to include a label. So the label is going to look like this and I'm going to type something inside of there. But more specifically, we're going to have label text. So constantly with text is equal to style dot strong like that. And inside a key, we're gonna do a display block. Font size is 0.9 rem, and then the margin bottom on these is going to be 0.25 rem. So the label text goes inside of the label. So wanna do label text here and then email like that for example. And let's just type a SDF there, see where that goes. So we have this over here, which hopefully should work once react hook formed downloads and it solves itself. Okay, so now that that is built, let's see what it looks like on the page. So I should just show email a SDF, but it seems to not be showing anything styled is not defined. So I forgot to include import style from starred components like that. Let's do that here. And now let's refresh. We got email and ASD F. So now instead of showing a is the F, let's include one for the text input. So for the text input here, we're actually going to go into components, new files shared forward slash text input ab.js. And the reason for that is because a text input is generic enough that any component that we build that surrounding text input, we should consider component ising and putting aside for modular reuse. So we're gonna go here. My import styled from solid components like that. Wanna do constant text input is equal to style dot input like soap. And let's, let's do a couple of things here. So first one is box sizing, border box, displayed block, font size 0.9, rem You're going to be 0.25 ram and the width is going to be a 100%. Now we export default text input here, and we actually have one more style we have to add inside of here. But before we do that, let's go into index.js and I'm going to show you what I'm gonna do here. So we're going to go into SRC new file and create a new file called a the'm dot js. So specifically, the theme consists of the colors that you use with any project. Now this is something I like to do because in a project, especially one that gets lodge out, it starts to become more difficult to have a coherent design language. In other words, that your, all your components kind of look the same, feel the same, so and so forth. So you kind of want that consistency and a great way to get that is to have a set of theme constants. And part of that generally includes our simple range of colors. One of the colors I'm gonna use here is I call very light grey, and I get that name from this website. So if you just search colonnade and Hugh, I use this one here to give basically a wide range of colors, different names. So for example, if I go here and the color I want to use is actually six season a rope. You'll notice that the name of the color is very light gray, so that's the one we're going to use here. Export cons, very light gray is equal to hash, and then six seems like that, and we have this color in here. So now what we're gonna do is inside of index.js, we're going to go in here and then do impulse or as a theme from the sludge thing. So I'm going to grab that theme and let's do a thing provide out inside of salt components like that. And instead of rendering this, we're going to end up a thing provider. Theme is equal to thing. So basically this allows us to use the theme within Alice style components. So being provided there like sorrow as well. And inside of text input, we are going to do border, one pixel solid. And then we're going to do this weird kind of template function syntax that we do at passing the prompts and we do a prop starts a theme dot, very light gray. So basically, approximate thing has always has access to this theme object that we passed in and we have access to very light gray. So that's one we're going to use and we pass that in as the border. And now if we have a look on our page, if we include the text input. So firstly, go here, import text input from hash. Routes for subcomponents, false are shared and then text input like that. And we go down here underneath label text. Let's do a text input and its disabled if it is in fact submitting that name is going to be e-mail, the type is going to be email. And we're going to register that inside of React hook form. So now we have this. Let's grab this and duplicate it. Let's change this one to be our name as possible. Type is also password as well, which is nice, and the label text is going to be password. So we have these two fields here on the page. And now you notice we have email, we have password. And the reason we put this label around it so that we can click on the text and it will take us into the field here, which is really nice. So now that we have these two, let's actually, Let's also add in the login button. So the Login button would go up here. And all we really do is login button equals style dot button. And we're gonna do a display inline-block. We do dislike and like walk because that allows us to give it a margin, top, margin, top here we're going to do 0.5 run like so. And we have our login button, which we're going to include key. So Login button type is to submit and we're going to write log in. So this one here should also be disabled if it is submitting. So disabled equals is submitting like that. And then we do that. Suddenly have this. Let's have a look at our page. We have email, we have password, and we have log n. So now if we open up the console and just maybe put that down here, let's make the console little bit bigger. And here for the email and password, lets us try say for example, tests at example.com and for the possible like so. And you see we got a test, example.com and password. So that is working just fine, which is great. But now instead of just console logging inside of here, we're actually going to have to do something with it. So in order to do that, we're going to have to include some graph QL stuff. So inside of here, inside a package JSON, let's start including the stuff that we need for graph Q0. So specifically, let's first go to the classifies up. So inside of here we are going to do yon add Apollo cached in memory. We're going to do Apollo clients, Apollo link HTTP to make sure that is correct. Yes, it is. We're going to do a graph QL graph Q rel tag as well. And we also go into do a polo or react to Apollo, salsa do at Apollo for such reacts hawks like that. So now let's press Enter. So now we have a whole bunch of stuff inside of here, which is pretty cool. But then inside of index.js here, where we have our global, we are going to include another provider. But before we do that, we have to include the API of the actual graph Q0 client. So right-click SRC, New File API forward slash graph Q0 client dot js. So now inside of this hall here, let's do import and then let's do Apollo clients from Apollo clients like that. Let's do import HTTP link from Apollo, link, HTTP like that. And let's do it. Import in-memory cache from Apollo, cache in memory. So let's do those three and then export caches unable to in-memory cache. I'd like to exploit it, and I've mentioned this before because sometimes I use it, but in this case here I'm exploiting it for really no good reason. So you can choose not to if you don't want to. Cause client equals new Apollo client like that. And we're going to use this cache. And for a link we're going to do new HTTP link credentials. It's going to be included. So this allows us to work with cookies and sessions and all that kinda stuff. And we're going to do your eye and then processed dot m dot services URI plus forward slash graph QL, export default client. So now we have this file here, but we actually don't have process m services URI. So in order to include this, we're gonna go into classifies out, create a new file and call this one taught ENV. And inside of this file here we are going to do services. Uri is equal to HTTP localhost 7 thousand. So the reason that we do this is because this matches our services URI here. And then we add forward slash graph onto the end there. So we have ENV and we also have ENV dot example because dot ENV will be ignored by gitignore. So we kind of include adult dog example file here as well. So now that we have this file in that one sets up, let's include this inside of index.js. So we're going to go up here and we're going to write impulse, hello provider from reacts, Apollo like that. And we are going to go around our theme provider and we're going to add Apollo provider. And then we are going to write a client is equal to Correct QL client like that. And we are going to include graph kill client or from the API. So import graphs you'll find from hash routes forward slash api slash graph Q0 clients. So now we have eight graphed your client that we've hooked up. Let's try yon watch, make sure that everything is working just fine. Okay, everything seems fine to me. And then over here it seems to be running. So let's continue now. Inside of, inside of login here we found our login and components. And inside of here we are going to include a mutation. So specifically we're going to include the mutation. In order to log in. So to do that, let's go to the very top and let's add an input use mutation from Apollo, forward slash react holes. And let's also add an input GQ held from graph kill tag like that. So we have these two here. And then now underneath Alice DOD components, but above L component here, we are going to add a mutation to quantification equals g, q, o like that and wanted to mutation. And it's going to have an email which is a string and a password which is also a string like that. It's like that. And we're gonna do a create user session. And we're going to pass in the email variable and pass in the possible variables. Not really hard coding anything here, which is really nice. So we have the ID and we're also going to pass any user email id. Now before we continue this up doesn't actually currently work. So let's grab this, use a bit here and let's try it inside of our playground. So remember that this is working just fine. But if I go here and I add in the user, you'll notice that now it breaks because it doesn't have any way to resolve this. So in order to fix this issue, let's go back into API Gateway. And we're going to go into SRC graph Q0 resolvers. And he, instead of just having me touched in query, let's add an another one for user session. So this is going to be a customer's alpha that we're going to add onto a property which belongs inside of user session. So now he underneath mutation in query, let's add int user session. And let's put the user session here and use the session. So it's going to be an object like fat, which we then export default. So we do that and inside of here we are going to pass in USA. So specifically this is going to be an async one, but takes into user session. Now, the first one here is the object inside of our resolver. Now the object refers to essentially the contextual value, the contextual object on which this is running. So in the case of user session, this will be the user session object. If this were on the user graphical type, then it will be an instance of that. So that's kinda how this value changes. And then inside of here we are going to do return. A white uses service dot fetch use up by the US id, which is going to be uses session user ID like that. So remember how they use the session contains a US ID. We're going to use that to fetch the USDA. So obviously we need to include it uses service from hash route for slash adopters folate such uses service like that. And inside of uses service here, we need to add in fetch user. Now you'll notice once again, I've said this before and say all the time, is that with microservices, there's a lot of updating everything in quite a few places and there's really no getting around that at this moment is that we have these kinds of separate a consents. And because we want to keep them separate, some code we need to write many, many times and hook up many different things to get one thing working. So now he had four fetch user. What we're going to do is we're gonna do constant buddy is equal to awake that got doc yet. Yeah, and let's actually put this one above this one here. And the reason for that is because we have create user fetch USA, create user session. And we're going to also have like Fetch uses session and stuffed down that. So we're gonna do a got dot, get like that and then uses service URI. And we're going to do forward slash, uses four slash user ID. Now if you're paying attention, you'll notice that we actually haven't built out this route here. So once again, we're going to have to go into the user's service here in order to build out this route. So now it's going to serve up, go into route's here, and we are going to add another route here. So specifically on the key, we're gonna do app.get forward slash, uses forward slash user ID like that. And we're going to do async or the request response. And next, like son. And we wanted to try and then confuse that equals a wife find by P K. So once you find by the primary key, which is the ID, and we're going to take in the parameters, the user id. And then if we cannot find this user, we return a new era. And so it's going to be invalid user ID like that. And then we do, if we can't find the user read to return res.json and the user like that. And then if we get an arrow, then we do return next and we pass that era along. So now that we have this functionality in all three places, ideally, we should be able to fetch the user inside of this one here. So now if I press play, if everything works, now you see we get the user in that which is really nice. So now let's go back into our classifieds up. Definitely huge tangent there, but there's not much we can do. We have use the email ID. And then inside of here we are going to actually use this mutation. So in order to do that, let's go here and let's write a closed square brackets create user session is equal to use mutation, and we're gonna pass in that mutation like that. So now inside of here we're gonna make this one async. And let's just say, let's just do a, let's say result equals a white create user session. And we're gonna pass in the variables. So totally Rice's variables, email and password like that. Now we have the result and we're gonna do console log results like that. Okay, great. So now we have result, console log result. And let's have a look at our page. So Pedra seems to have broken and it's because we don't have regenerate a runtime. So in order to fix this problem, all you have to do is inside of index.js at the very top here just to import at bubble forward slash poly fill. And once you do that, it should start packaging, build it, and then everything should be working just fine. So now anyways, we got this one here. Let's try logging and so test one at example.com, like that. And then the possibility is just password. So now if we open up the console again and click logged in, you'll notice that here we have data dots or create user session user. So everything's working fine and it's actually allowing us to log in. So basically the login functionality is complete. But the only way we can kind of continue with the login component is if we have a way of fetching the actual user's current session. So in order to do that, let's go back into our user service over here and we're going to try and figure out if we can get information surrounding the user's current session. So now inside of routes over here, and what we're gonna do is we're going to add underneath, adopt host sessions. We're adding here, wanna do dot gets bullets such sessions forward slash and then Session ID like that and do Async request response and next like that. Then in Saudi key, we're gonna do a quick try. Uses session is equal to m. Very similar, uses session dot find by pk requests dot params dot session id. So remember that we're passing in the session ID here. So I'm just going to try and find that straight away, like the star. And we're gonna do if the user session cannot be found and we do return next new era, and then it's going to be invalid session id. However, if it can't be found, we're gonna continue and do returned res.json where if the user session and if we get an era, as always, we do return next E and we pass that era alone. So now we have this bit of code here which allows us to fetch any given session with an ID. So now inside of API Gateway, what we're gonna do is inside of server here we're actually going to include. A custom piece of middleware. So the way this works is we're gonna create a new file, new file inject Session.get AS. So for this fall here we're gonna do import uses service from hash roots, adapters and then obviously use a service like that. Injects session is equal to async and that request response and the next set of requests and responses next like so. And then if request dot cookies and you might remember this keyword here, use a session ID which is the same one we used inside of mutation here, crazy session. So we use the same user session ID for the cookies. If this one does exist, we try to get that session. The client's user session is e to a white uses service, not Fetch, uses session, and we fetch it by the Session ID. The session ID is request, I'll cookies dot useless session ID like that. And then dot locals thought user session is equal to user session, so it responds to a local resident. Locals is basically a custom object where you can store a whole bunch of stuff. And one of the things that we're storing it inside of here specifically is inflammation surrounding the user session. So that's what we're gonna do here. And either way we're going to return next, which moves us on to the next piece of middleware. So now we do that with your export default inject session. So something like that just to get it moving on. And now let's include this inside of starts server. So underneath Phonograph Co. errors, let's do inject session like that. I'll describe inject session and then above here and above the Apollo southern bit and underneath cause I wanna do it app.use inject session just like that. So now that we have this section here in our code, we need to go into user service and we need to actually define fetch user session because we currently do not have that. So we have create user fetches or create user session and fetch users sessions are only that makes sense. Fetch it by the Session ID. So we pass in Session ID here and we do quants the body equals, I'll wait and then got to dot get. And then obviously this one here again uses uses service URI and then forward slash sessions forward slash and then Session ID. Like that's only part of the session ID in. And then we do dot JSON and we returned the body whatever data we get back. So we have now Fetch uses the session, we have inject session over here, and we have that inside of stamps. So we're actually going to do this is inside a typedef here, inside a query. Let's include a way for the clients or the front-end user to fetch if they are currently logged in or whichever session they're currently using. So we're going to use is one called user session. And this is going to take me, which is a Boolean. So at the moment it's a Boolean, riches required. So basically this one has to be like you have to fetch itself. But the idea is that in the future it can expand to fetch other user sessions. However that my work. And then it's on key, it returns a user's session or it doesn't. So we don't want to put an exclamation mark because if the user's not logged in, then this will return null. So we don't actually want to put an exclamation mark. So we do use a session like that. And then inside of query here, and we're going to add that in. So export default as user session. Right-click new file uses session ab.js and we're going to copy the one for listings guard. Take this one and we're going to use those session resolver inside of this log here. This one's a relatively simple, is we're going to just use a request. The first one is OBJ arts and the context. And then if OG stopped me is not equal to true, like I said, we're only supporting true at this time. So we can throw an error, say unsupported argument value. And then what we're gonna do, the term context, I'll raise the locals thought useless session. So I'm going to return the session from there. And basically it allows us to access that. So now that we have this, let's go back here. Let's refresh, zoom this in a bit again. Okay, now everything does seem to be running. So let's go over here, refresh, and we should get the graph Q0 interface showing up. For some reason it does not seem to be showing arrow we're getting is an internal 500 Silva era. I think that might be due to the fact that we included this inject session thing here. But it does not seem to be telling me what the problem is might be related to. The Fetch uses session here, which is fetching from H0, which is going to use a service URI sessions and then the session ID. Sir. Seems like we have a bit of debugging here to do. In order to fix this problem, it's probably best to have a look at. Key is let's talk hatch and then grab the ERA. And let's do console.log, e dot response.body. So let's see what the actual body of the request gives us. So now let's refresh every key and we should get an error pretty soon, hopefully. Ok, so the error is cannot read session property, session ID of undefined. So if a fish user session here, we're doing a request, they'll cookies, dots user session id. So this shouldn't be an issue because we're doing a request, the cookies dot user session ID here. And this error actually is coming from the users service since IT uses service here, let's go back into routes. We do sessions here, we write requests, palm, palms. Okay, that's totally my bad. Should be requested programs. But anyways now let's get this out of the way. In terms of error handling, I do have a general narrative. If you have any questions like, why you doing this this way isn't this way better? My general comment is this, which is that this project is done mostly with microservices in mind. I do try to cover as many of the best practices as I can given the size of this video and obviously the duration and complexity, all that kinda stuff. And then I chose to make a few shortcuts. For example, in times of error handling, in terms of the overall small miscellaneous design choices, I try to keep as minimalistic as possible. So anyways, now let's try and see if we can get this one working. So we do curly braces here and we do say, for example, use the session and the truth. So actually before I run this, we need to get something from the Chrome webstore in order to see if we have the cookie actually inside of our browser. So let's get a cookie here and we should get something come up pretty soon. So let's do edit this cookie. This is the one I like to use. Click add extension. Great. So now over here we can refresh on the playground and we have edit this cookie thing. And you'll notice that we have used a session ID and it does have one inside of here. So what that means is that this should return us the same ideas that, and this one here is nine CF something. So let's see how this goes. So we get unsupported argument value, even though it does seem like we passed in the correct value here. So let's see what's going on. If we go into here, use the session we got onStop me l, sorry, this one should be Alec's domains like It's true, like that, not with an exclamation mark at the front. So that's very flat to restart and click play all the time and we get use this session is null. Now that's really weird because technically it's shorter written this, but it seems like we're not getting inside of this pot here. So let's go into inject session and see what's actually happening here. So let's do a console.log session and let's see what we get back. So every keyword restarting, and then we wait for it to start it. Okay, great, so let's click play and we're still getting back nothing that it doesn't seem to be going inside of here. So it seems like our cookie actually isn't being recognized at all. So let's have a look at our request. I'll cookies and see what's going on there. Or maybe if it's even running this function at all. So I'm kinda having a few questions here in terms of debugging why it isn't working, but we have to try and figure that out. So it seems like we get an object with an old prototype and there's nothing inside. So basically, we are not getting any cookies at the moment. So we do have cookie-parser here. I think that the reason it's not liking, and if I remember correctly, is that the default graph Q0 playground actually doesn't allow you to have cookies basically be passthrough. So in order to fix that, we just need to go to this page here. So right click Settings and then for credentials, instead of using emits, we're going to use include CINAHL, it's mature command S. We saved this fall or press this button here. And let's go back here, press Palais, and we get our session ID. So now if we do use all we can do ID. We can also do the email. So now we have that information here as well. So that's really cool because now we can actually start using this in the front end. So every key inside of the classifieds up, what we're going to actually do is start fetching that inflammation and we're going to store it inside of redox. 8. Storing The User Session In Redux: So now what we're gonna do here is just going to SRC. You fall here, Store forward slash index.js. So this is going to be our Redux store. And inside of here we're going to write our import combined with uses and also create store from lead us like that. And we're gonna do once that reduces is equal to combine reduces and ducks. So we're going to create a couple of ducks and we're gonna use the ducks pad and so do dogs here like that. And we do a constant reduces is able to combine reduces ducks. So we're gonna do the duct pattern here, and I'm gonna show you that in just a second here. But we're gonna do a constant store is equal to create store reduces. And we're going to do Window dot, underscore, underscore, redox, underscore, devtools, underscore, extension, underscore, underscore and window dot, and then the same thing again. So you're gonna grab that, put that here, and we're going to run this function. And I want to do export default store. So this bit of code here or with the window here is a completely random, but essentially this is in order to get redox dev tools working. So it actually is in fact quite important. Now we need to include ducks. So we're gonna create a duck's directory. And inside if there put a file pointer index.js. And index.js is literally just going to export the session there like that. And this is essentially the ducks pattern for redox is we have our actions here on the top. So we have constant clear is going to be session for such clear, set is going to be Session four slash set and then constant, the default state is going to just be null. And then our reducer we're going to put here and then cons session reducer is equal to two state is the default state. Action is going to equal two curly braces like that, and then switch action but type. And then for the action, if the action is a set action, we're going to return action not session. If it's a clear, we're going to return null. And then otherwise we're just going to return the state as usual and want to export default procession reducer. So we exploit that. And then we're going to also have action creators. So the action creators basically used the actions in order to generate these actions objects. So the actual action names themselves and then regenerate the objects from that. So the first one's gonna be export const SET session is equal to, and this one takes in a session like that and we're gonna do it, return this session, and then type is going to be set. So we set for that SET session and then export points, clear session. This is molecule kind of Logout typing is equal to and then just round brackets like that for a curly brace. And we're gonna do return and then type is going to be clear. So we have SET session, clear session or this kind of stuff. And then inside of here we're doing all of this. So now we're going to include this file inside of index.js. And in order to do that, let's first do import curly braces provider from React Redux. And then over here, once again, we're going to wrap it in something else. And this one's going to be the provider and then provide R. And we're going to do store Is equal to store and we get the store from the store directory. So import store from store. So now we wait for that to resolve and do its thing. Great, so now that it's built, let's go back here into classifieds up and you'll see that there really isn't too much of a change. But we do now have the reducer in order together working, let's install the redox step towards extension if you haven't done so already. So redux dev tools and let's grab that one. The only complete here is dodgy and it doesn't work unless you have the full thing done. Anyways, it's kind of it anyways, let's add this one to Chrome. So just this one here should be called remote div or whatever. And now over here in classified the outlets where refresh and there we see the icon has gone green. And you'll notice that we have init and we just have an empty state with session being null. So now if we want this to be something more than we have to find a way to initialize that. So we'll actually go into do is inside of components root over here. We're going to initialize that inside of here. So firstly, you, let's go up into react here and let's include a US State. So we're gonna include a state variable that sounds going to be caught initialized. So this one's just got me a simple Boolean. So set initialize like that and then use state and initialized by default is false. Now, if it's not initialized, we're just going to return loading like that or something along those lines. Let's include US effect here as well. And let's do use effect like so what curly braces here? Square brackets there, and inside we're gonna do our graph Q0 client query. So firstly, let's go up here. Let's do import G20 from graph QL tag. So this is for writing a graphical queries. We've used this one before as well. Infographic your client from hash route API graph QL client like that. And then we're going to do right here constant query. Actually let's do this one below so we can see it. Query equals G30 like that. And we're gonna do curly braces, user session and me is true. So I'm gonna fetch the current user's session, including the ID, the user. And then it's going to contain the email and the ID like that. So now for the query that we're going to run it inside of the user effect. So we're actually going to graph your client dot query, query like that, and then dot then. And what we're gonna get back, we're going to restructure the data. And then if dot-dot-dot user session, in other words, if this is not null, then what we do is we set it so we do round brackets, curly braces, dispatch, and want to include this in just a second. This is for Redux dispatch SET session, dot-dot-dot user session like that. And regardless we're going to do set initialized to true. So only setting the session if it in fact does exist. But either way we're going to initialize the page. So now we're going to include dispatch and that one is from reactor redox. So import used dispatch from React redox. So reactor redox recently added support for hooks, which is pretty cool. So we can just do quants dispatch is equal to use dispatch in order to use that. And four sets session just underneath here we're gonna do import SET session is equal to hash route forward slash store for such ducks forward slash sessions. So this SET session comes straight from the dock. And this one here which contains SET session, which runs this whole thing, takes in session, which is why we're passing that in inside of heat. So anyways, now that we've done this, let's go back here and it should say loading, but it should also respond. So it has an invalid hope coal, not traditional. Why that is the case? It's because I'm not running US dispatch, so I'm gonna just do that real quick and that should work just fine. So now if we actually have a look at our redox dev tools again, you notice we have init and then we have sessions sets, and it actually sets the full session here. So inside of here we have the user and everything. The whole session has been set. So now what we're gonna do with that is inside of root here, instead of directly rendering and login, we're actually going to read the account details. So let's create a new component here. I'm gonna call this one account details. So account details, account details about js include a file like that. Right-click New fall again, index.js like that, we wanna do that. So this is a very simple component. But then inside of here we're going to put login. So basically instead of rendering login, we're going to render account details here on the sidebar. And then account details is in turn going to render login conditionally depending on whether the user is logged in. So the way this component works is we're going to include login here like that. So we're actually gonna do import use Selector from reactor redox. So this is the way that we select data from Redux. And then inside of here we're going to close the session is equal to US. Select up. And we're gonna kept the state and wanna do state DOT session. So we're gonna get the session from the state like so. And basically, if the session does exist and we're going to return the accounting components. But for now let's just return the texts accounts. And then otherwise we are returned the login component. So we basically have a conditional inside of here, a switch of sorts. So you see, it says account, but if I actually go here into redox and let's just say I jumped to a before this thing happen. So let's move this one out here and move this one here to the side. Do that, and click on this button here. And we do type session forward slash clear, that should include the session. So now over here you'll notice that where we have, we're actually currently logged out. So if we go forward, you see it's logged in. But basically if we run session clear, then it will clear it and all log us back out. So that's basically what we're trying to do here. And obviously for the account page, we're going to add in the functionality to actually allow them to log out. But that will have to do more with the backend as well. So now we have login RV, hey, let's also add in account. So right-click, you fall account, account dot js like that. And then we're also going to add in index.js. So actually inside of account key, new file index.js and include it like so. And we have accounts which is going to be just a simple component like that for now. But then inside of this file here, we're going to use the same use selector. So we're going to grab the session as well and grab this line here. So we have the US select, I'd end the session, and then we're going to include a couple of styles using stalled components. So inputs diode from subcomponents like that. And the first one we're going to do a Firstly, let's go into theme here, and I actually have another color I want to use the Choose Export constant. More talk is equal to N, a much darker shade of grey. So these are called the names I got from that same website a couple a little while ago. And that's what I want to use here inside of this component. So you generally try to use them sparingly in terms of like, you don't want to add too many colours, but you try to use the same ones consistently. So this is something of a design language which you generally try to decide on beforehand. So we're gonna do something like this. And inside of here we're gonna write color and then props, prompts dot the'm dot water. And we're going to do font size is going to be 0.9 of Rehman. So something like that. And then ala rapidly and what going to do logged in as, and then we're going to write Session.get user.email. So now let's save this here and let's see if this works at all. So we have accounts on the page, but we're not actually rendering the component. So we do important accounts from a count and we do that, and we do that so that we save this go to heat. And you'll see it says login as test1 at example.com. But let's format this a little bit better. So what we're gonna do is they're heat by cleansed email equals style.css as well. And this one's going to be color, but this one's going to use a slightly darker shade of grey. So we're going to use export constant Nero is equal to the hash 222222 like that. And we have near Rohit and this one's going to use that. So we're gonna do color and then prompts a prompts dot, the'm dot Nero. Font size is going to be one rim. So a little bit bigger as well, and much in top, we're gonna just put 0.25 rem. So now let's go around how email and let's just, oh, I should've wrote email not occur. So we're gonna do that and get rid of this apostrophe at the end there. So we have email on ala components. So now we see we have logged in as test one at example.com. So now this is enough to show the actual account on the page here. But what if we needed to log out, then what are we going to do here? So we actually don't have the specific functionality to allow us through logout at the present moment, but we're going to build that out now. 9. Logging The User Out: So let's go back into VS code over here. And for VS code, we're going to go into what we're going to fix up some stuff inside of API Gateway and we're going to add something into users service. So inside of uses service here for the routes are going to add in a route in order to delete a session. So this one we're gonna do above here, above doc, yes, do app dot delete and basically the second party. So instead of guessing a session, we are going to delete it. So async requests and next like that, try to use this session to await, uses session dot find by pk requests not params dot session ID. And actually it's exact same part as this pond down here. So we have to describe that. Do this, and we're gonna do white user session dot destroy. So want to delete the session entirely and the return from res.end. So we're going to end it there. And then if we get any sort of arrow, we're going to return that error inside of next life. So now we have update delete setup. This is how you delete a session, relatively simple, but we're going to have to write big accompanying code inside of API gateway. So inside of graph killed here, let's go back into typedef fs. And we're going to add in a mutation which is going to be deleted user session. And this one's going to take in a session ID, ID like so, and we're going to do Boolean. So ID and then boolean like that. So it actually returns a true or false delete user's session. We're going to add back inside of resolvers mutation new file, create this file here, delete user's session dot js, and we're going to export default that inside of here as well. So for delete user's session, I mean, at this point it's pretty much the same format as the rest of these. So let's just grab this one here. Instead of create user sessions with only to be delete user session. And instead of taking in email and password, it just takes in a session ID. So we do delete user's session are with the given session ID. And then instead of setting the cookie, we're gonna get rid of 14. So we do a context dot, dot clear cookie user session ID, simply like that. And we can set a returning user session. We return true. We can't do that as well. So we'll just do our delete user's session like so. And then inside of users service, let's add in the delete user's session method. So underneath create user session, let's do static async, delete user session. And this one here takes in a session ID and something like that. And then let's just do, for example, a const body includes a weighted graph dot delete. And then we're actually going to return the data, even though it's pretty much useless at this point. Anyway, sessions. And then just do Session ID like that, and then do dot JSON. So we get rid of it and we return the body. So this is just for deleting the user session. And then this one is hooked up and this one here should be working. So now if we go into the playground here, Let's have a look at the current session, which is 9609169441 is here. So now if we actually grab this ID here and we are trying to do a mutation. So mutation delete user's session. So maybe refresh. We should have access to it. Yep, swayed. Okay, so session ID here and we pass in that session ID. And let's just see, because this one gives us a Boolean, we can't really put any curly braces or anything. Let's just click play and see if that works. So now we have deleted is true. If we go the heater cookies, you see that the cookie is gone. And if we go here, we're logged out again. So now this is working just fine, which is really cool. So now we have delete user's session setup. Let's go into our classifieds up. Let's go into. Accounts over here and inside of account, we're going to add in the functionality to actually log the user out. So here we're going to add an import, use mutation or from a polar react hopes again. So apolar reacts hooks, and then we're going to add GPL from graph QL tag. And then with these two here, we're going to do it. Constant mutation is equal to g Q_l and kinda do mutation here. Basically copy this one here is fine. So something like that. But we're going to take in a session ID argument here. So session ID is going to be an ID and this one is going to just be Session ID like that. So now we have a mutation. We go here and we do square brackets. Delete user's session is equal to use mutation and that mutation like that. So we have the mutation here and underneath email we're going to have what I'm going to call a log out link. So here we're going to do constant logout link is equal to psi L dot a, but attributes and an HRF, just a hash like about two, something like this. The color is blue, display is block and margin top is 0.25 rem. So now here underneath the email we're gonna do logout link. And then unclick is equal to EBIT, EBT dot prevent default. So we're going to prevent it from, you know, creating a hash basically. And then we're gonna do dispatch clear session. So I'm going to have this in, in just a second and then delete user's session. And the variables for the session ID. We're going to take session dot ID like that. And now you notice that we didn't use async on this or a weight for it or anything. And the reason for that is because we really don't care when the user session gets deleted, what you've already done it clear session which quote unquote loves the US OUT from their point of view. But then delete user's session is just the server-side thing. But we don't really care on regarding when that actually completes. So we do something like this and we just do like logout link like that. And then now let's add in the dispatch. So when I go here we have use select already. Let's add in a US dispatch and we're also going to get clear session. So important, curly braces, clean session from the hash root store docs and session like that. So we get a clear session function here, and that's what we're going to use here. Dispatch is equal to use dispatch like so. And then we're gonna dispatch close session and then delete the user session like that. So now this should actually be working just fine. So if we go into classifies Apple currently not logged in, we don't have a way to login as of yet, but we can first create a user session and then do that. So we've got over here the email and the password, so we create a new session and that should get us logged in. We refresh over here and we're logged in. And now if we click Log out, natural log us out, and then over here it should be gone as well. So now I'll Logout works correctly, but I'll login isn't actually properly hooked up. So now we're going to go into login again. And you'll notice that over here we're just console logging the results. And instead of just console logging it, what we're gonna do is we're going to actually, instead of just only result, let's just be structural straight away to get data and get our creates user session, which is the name here. So you get the same name here. And I'm gonna call this one I created session or something like that. And instead of just console logging, We're gonna do dispatch SET session and we're going to create a session. So very similar to the other file. We just need to go here and add in Import, use this patch from reactor redox. And we're going to do import curly braces. And then we're going to add in the code set session. From the hash root store and then docs session like that. So this is for setting the session and that code there should be working just fine. Well, we need to add in our dispatch as well as the constants patch is able to use dispassionate like that. So now we can save, we can refresh and you see where currently not logged in. But if we do test1 at example.com with password and we click Login, then it should lock us in. And then now we refresh, we're still logged in. We click logout and that logs us out. We can try a different user if we have one. So we have test too as well, test2 at example.com and password logs us in as test two, and then we can click logout to log us back out. So that's working just fine, is working really, really well. So now we have the ability to login, we have the ability to log out, but we don't currently have the ability to sign up. Now in terms of signing up, we're already hooked up pretty much all of the backend. So we have create, use OLS that built, or we have to do is add in a signup component. So the way it's gonna work is inside of login here. Underneath the login button, we're going to add in a component quarter or sign up. So this is going to be essentially an option that you can choose on instead of logging in is to first sign up. So we do all sign up here and then we just write all. And then a H ref equals hash onclick equals curly braces EBT. And let's just first do AVT dot prevent default. Nothing too fancy. And let's just write sign up there, like so. So now for all sign up here, that sounds pretty simple. All sign up is equal to styled thought span or something like that. And then we're gonna do font size 0.9 rent. So what's gonna do that? This is all sign up and we are going to check out that link over there and it's working just fine. So now we just need a space between this one and that one there. So just a space there. So we have that space that, which looks pretty cool. It looks just fine. But now we need to get this one walking. So in order to get the sign-up link working, let's go into account details and we're going to actually use this as a switch. So we're gonna go here for react to and just I didn't use stapes bear. And we're gonna do signing up. Set is, signing up is easy to use, state and currently false. So it's currently not signing up. But then down here basically, we do if is signing up, then we returned the signup component, and then otherwise we return the login components. So right-click New File, a sign up, sign app.js. So something like that, right, Wheaton, you fall again, index.js and we include that here as well. So now instead of just including login here, but also obviously includes signup. So now we have a signup and a login, but we have no way of setting is signing up to be true. So inside of login here, we're actually going to add onchange to sign up as a custom event. And this one's going to be set, is signing up. It's going to be true. So let's actually wrap this in another county writes so becomes just a tad more readable to set is signing up is going to be true. And then inside of login here, we're going to pass in a prop. So curly braces. And this one is called unchanged to sign up. But we're going to rename it to push change to sign up because I didn't like running a function that's called unchanged the sign-up. So we do push change to the sign-up. And this one we run when we click on the link. So we push change the sign up there. And now let's go over here. And if we click sign up, it takes us to the signup component. So sign up is actually very similar to login. So we can actually grab the login component in its entirety and replace sign up here. And I'm just going to rename this obviously to sign up and a change this one here to sign up as well. Then for this one here, instead of all sign up, we're going to call this one all login. And this is going to be or login here. And then instead of push change to sign up, we'll actually describe changes sign up there. And instead of changing the sign up, it's going to be changed to login. So we have push changed login, changed login here, and pour change log in there as well. And now this one is called sign up. So this is MOS signup component. And instead of a login button, this one, it's going to be called Sign Up button. Sign Up button like that. And instead of a login button up here, sign-up button here, and move that down there. So now we have this component here. I didn't know if it works, but let's just first have a look, see how it looks. So you see we have email and password still. Before the signup component. We're actually going to make it a little bit more complicated. So we have email here and we have password, but let's duplicate postulate and tennis one to confirm password. So we have obviously possible to confirm password, pretty standard practice here. And we're going to make this one a confirm password like so. So now we have email password and on here for the sign-up screen, we also have confirmed password. But in order to actually sign up, you have to make sure that the form is reasonably well filled out. In other words, the password and confirm password i equal in value, that sort of thing. So we're going to do is for the sign up button to work. We're actually also going to disable it if it is not balanced. So if the form is not valid, and we're going to determine that through our use form up here. So inside of US form here we're going to add in a mode is going to be unchanged and we're going to add in is valid here like so. So now that we have that, we're also going to add in something called a validation Schema. So we're going to add validation Schema, heat and reacts quoque form uses a validation library. Caught, yup. So why UP? Funny, we do constant validation scheme again is equal to Yelp dot, dot shape like so. And we do email, yup, dot string, dot required. So it's a required string can't like, sorry. Possibility is, yup, thought String Dot required dot tests. So actually going to add in a custom test here, same as confirm password. You don't have to call it this, but this is what I decided upon upon there like that. I don't know what this is, but that is not the same as the confirmation password like that. And then we're going to take in a function, and this function is going to return this stop parents stop password triple equals this dot parents dot confirm password. So basically this checks if it is valid, right? And the only way it can be valid is if the positive and matches confirm password and they both can't be empty because we did not required on the password here. So now that we have this validation Schema, we have to include a Yup. So it's gonna go up here to input all as yup, yup, and shouldn't get us installing about. Cool. So now we have that and we have validation Schema here. Let's save that and see how this works. Great, so now that that's built, Let's go to sign up here. And the button you'll see is disabled. If I type in an email like a ISAF at gmail.com and from possible scale type 1234 and the cell type 123 or four. And then it's valid if I type five then becomes invalid again, type five here it's valid again. So I'll sign up form in terms of the front-end seems to be working just fine. But in terms of the hand or submit, we obviously need to change that part here. So what we're going to add is change this one here firstly to create user. So create user a here. And then instead of this mutation, we're going to change this one slightly. So we're gonna take create user and all that we needed to return is an ID. So we actually don't really care about the return value here, but we're just gonna return on just an IV here because I, these are nice. And we have email and password coming in and then go down here. And we're going to do a white create user. And we don't need any of the data kind of coming back. So we can just do variables, email, password, or maybe it put on same line like that. And then instead of doing a dispatch, lets first do a reset. So we're going to reset the form real quick insight of Reset from here. And then we're going to push change to log in. So we don't need to set the session or anything fancy. We just need to take them back to the login page. We don't need dispatch anymore. And as such, we don't need SET session and we also don't need to use this patch here. So let's get rid of those. Hopefully should still be working just fine. So that's sign up with test three, example.com. And the possibility is obviously possible, the n possible like so click sign up and it should take us back to the login page, which it hasn't little bit disappointed. But let's first see if it has added it into the database, which has, which is very nice. So that's very, very cool of it. And the reason it's not taking us back is because our unchanged to login and pushed Angel login hasn't been set up. So here we've got unchanged the sign-up. We just need to do a similar thing for unchanged to login. So we do this and then set is signing up is going to be false. So then it takes us back to login. So now here let's click Sign Up to test for at example.com. Password and password. Click sign up takes us back to this screen here and we do test, for example with AECOM and then password. And now we can log in. 10. Adding Listings Using GraphQL: So now there isn't too much to do. But what we're gonna do now is basically just finalize, et cetera. We have our listings on the page and we can add a new listings as well. So in order to do that, let's go back to VS Code. We have account details here, inside of roots, but inside of content here, we want to add in a component quoted listings. So the way it's gonna work is just inside of here. Let's just add him listings like that. And let's just import listings from listings. So now right-click route new file listings for slash listings dot js. We do something like this. And then right click and you fall again, index.js and essentially do the same thing. So we have an index and then listings file, and we're showing that on the page. So really, really simple so far, just showing listings here. So now instead of just doing that, obviously now we're going to add in some functionality. So what we're actually going to use is the use of query hope. And I don't imagine we've used this before, but now we're going to put it into this project. So from Apollo react hooks as well, input GQ all from gruff que ella tag and AL query is going to be PointQuery is equal to g, q, l like so. And then curly braces, listings, and then description, ID and title. So if you remember, we kind of created this way back. So we can go here and paste this in and it shouldn't just be working just fine. So you see we can fetch our listings. So we can just use this straight away. So now we're gonna do constant thought-out and loading is eager to use query, query like that. So we'll use this query. And then if it is in fact loading at the present moment, then we return a loading dot, dot, dot. And then otherwise we're going to return a rapid and we're going to show you all the listings in that. So now before we write this out, let's add in some styles for Alice stuff. So input style from style components, but we're going to add a description for the, for the listing. So star dot p and this one essentially just has a margin bottom of 0. Everything else for this one is a fine listing equals style dot div. Like that. Padding is going to be one RAM top and bottom 0 left and right. And if it's not the last child wanted to border bottom one pixel solid, crops prompts dot theme, thought very light gray. And let's do constant title equals style dot strong, and then display block. Font size 1.5 rem and font weight is going to be 700. So now we have description, listing and title. And inside of here we're gonna do a return, a festival, a div. And then inside of here we're gonna do a dot-dot-dot listings dot map. So at this point the listings have already loaded. At this point it hasn't loaded yet, which is why I chose loading dot map and then we do it listing like so. And then listing key equal to this thing got IID like so. And then inside of keywords do title, Listing, dot title and description, listing dot description, like so. So now that we have this one set up, let's save that real quick and go over here and you see we have cowboy hat, yea h4. So now let's add a different item. So I go back into the listings database here and number two, and let's just say thus drink bottle, which is on my table right now, I'd like to use the string quote-unquote a lot. And for the description, let's just do stay hydrated. My Hermes semicolon and 0 semicolon Zimmer. And then let's do it now and now like that. So now we have two items here, and you'll see it shows two items with a line. In between. So we have cowboy hat and Vos drink bottle. Now, before I continue any further, I do actually want to show something here which is inside of graph QL. We are currently fetching information regarding the listings. But what we can do it in a single query is not only fetch this, but also fetch information surrounding the user session. For example, ID, user ID and email, something like that. We can click play and it will work just fine. Currently we're not logged in, so let's just log in real quick and the showcased that. So now let's click Play again and you see we get both information for listings and for user session. Now what's so cool about that? What's cool is that in a single graph QL query, we can fetch information from both the listings microservices, and also that uses micro service as well. So that's what makes graphical really great, is that it doesn't really directly specify which queries are okay and which ones are not. But it kind of says, Hey, you can kind of compose this however you want based upon an existing schema. And that comes in really handy here because it gives us control with graph q, l. It really doesn't care where your data comes from. So it's really great as composing different sources of data, in this case are different microservices. So that's why we chose to use graph here or here. It just makes it really convenient. I just thought that this would be interesting. So we have the cowboy hat and fostering partial, which is just fine. But now we need to add in the ability to add new listings. So in order to do that, let's add a add listing components. So Adam, this thing at listing dot js, I didn't just fall here like so. Let's copy that so I don't have to write it again. Index.js boiler index, add listing. And let's add in our Add Listing components here and then go here and import at listening. Now you'll notice that we actually do get a problem when we do that. And that is that this item here actually has a border bottom on the bottom. Which kinda makes sense because we're doing if it's not the last child, but now I'll add listing is the last job. So the really simple solution to this is just wrapped this one in another div so that the last listing will always be the last child of this div. So now you see we get rid of that line there, which is kind of one-to-one in this case. So if you kinda wanna keep outline, then obviously you can work with that. But in our case, I don't wanna do that. If you do want to keep that line, probably a good idea to just get rid of this not in the first place. But I feel like what I'm trying to do is get rid of that line at the very bottom. So I'm going to use a dif. So now in the case of Add Listing, it's very similar, I guess, to sign up or whatever. And we're gonna do here is first add in some cell components. So inputs thought from styled components like so. And go here and just write constant form equals style.css. And then background color. Prompt, prompts dot theme, and we're going to use white smoke. So this is another color I'm gonna use here. So export constant, white smoke is equal to and then f h, f h, f eight. So that's the color when you use here. Notice firstly, alphabetical order and also consistency in capitals. So these kind of things, I valid quite a fair bit just to keep consistent across the project. So we have white smoke over here and we're going to include that inside a cage. Margin tops Gandhi one REM padding is going to be one gram here as well. So now instead of using an H1, let's consider using a form. So let's do this and right form. Refresh and you see we have Add Listing over here. So now inside of Add Listing, we're going to put in a form that uses React book form. So important use form from React hope form like that. Go here and just to close curly braces and we're going to do of form state is some missing again and handle some knit register and also reset is equal to use a form and we're going to end it like that. And here we're going to do form onsubmit equals onsubmit. Onsubmit is equal to handle submit, async. And we're going to take in the description and title and just console logging that for now. So we have the description, the title which we're going to console log. Instead of writing listing there, we're going to add in our labels and the text inside of it. So I'll do it label again and then label text. This was going to be title. And a text input disabled is eeta is submitting name is equal to title, href is equal to register, type, equal to text. Now grab this, do a second one. This one's going to be description is able to is some missing names, IGDA, description, reference register. And instead of type equals text, this one is actually going to be a text area. So we have text input n texts area, text input we actually already have defined. So import text input from hash root components shared text input. But now we're also going to have to define texts area. So inside of shared here, let's create a new file, a text area ab.js. And this all is just going to be another cell component. So start from start components like that. Text area is styled dot text area like surf. Borda is going to be one pixel solid. Props, prompts, dot, dot, very light gray. And then box sizing, border box. Just slaves gonna be blocked. Font-size 0.9 Ren padding 0.25. REM, resize. There's going to be vertical only. So we don't allow for horizontal resizing and the width is going to be a 100% exploit default text area like that. And now back inside of here, let's include the text area. So we have both the text area and the text inputs which we are using down here. Now we don't have label and we don't have labeled text. So let's get those to define now. So we're gonna do a constant label is equal to a style dot label here. And this also is going to be the slave block. And if it's not the first child and do margin top 0.5 rem. And inside of here we're gonna do constant label text. So you need to style dot Strong. And we're gonna do just play it block font size 0.9, rem margin bottom 0.5, remnant like that. So now let's save this and let's see if we got everything. We need it. So we've got title and we've got description. Brilliant. Okay, so now we're going to add in our button. So for the button here just down the bottom here, Watson type is e to some net and this right add listing. And this one's going to be disabled if it is submitting. So disabled equals it's submitting. And then here we're going to add a constant button is equal to psi plus button and then margin top 0.5. Rem someone at work unless you add display block or display inline-block here. So I'm going to use this. And we have some nice spacing there. So now let's add in our mutation actually got this hooked up. So we're going to go up to the very top import curly braces. You use mutation from Apollo four slash react hooks like that. We're going to also include GQ over from graphic EOL tag. And let's add an odd mutation above the component. So of mutation is equal to g q o ISO. And they'll want to do a mutation taken the description and the title for the string. And then title is going to be the string as well. And we're going to do create. Listing. Description is going to be this. Title is going to be that. And then ID. Now we haven't built to create listing just yet, but we're going to be able to in just a second. Now before we use mutation, let's actually have a look and make sure that this is actually being returned right now. So let's go into hey, console that's just type in, say for example, ASD FQ WAR, and then that will come up here. So that's working just fine, I think so description first, then Title. Yep, that's fine. So now what we're gonna do is before we hook this up, let's get Create listing built or v here and the backend, sorry, inside of API Gateway it, let's go to typedef here, and now let's add in create listing. So to create listing goes and takes in our description which is going to be a string. And then we take an title which is also a string, and we return a single listing which is not null. So now that we have that, let's go into mutation here. New file create listing dot js. Let's make sure that this is included in our list of mutations that create listing heat. And we're going to do cleansed Create listing. It was Salva is equal to and then OBJ. And then for the arts we've undertaken with description and Taizu, something like that. Export default create listing resolver. So we're gonna do is import listings service from hash route forward slash adapters for slash listings service. So we do that. This one here is going to be async and we're actually also going to take in the context. So the reason for that is because if the user's not logged in and we don't let them add in a new listing. So if not context dot-dot-dot local woodlot user session. So if this is not defined and we throw an error saying that they're not logged in and as such, they cannot create a listing on the otherwise we do return, I'll wait. Listing, service thought creates listing, and then the description and the title. And I want you to pay attention to one thing here, which is that the actual authentication is being handled by the API Gateway. We actually don't want to handle any sort of that kind of authentication stuff. Like for example, inside of listing service, inside of user service, inside of every other thing. We only want to handle it in as few places as possible, but keep those places is critical so that all requests are authenticated properly. Because if you do authentication all over the place, it just becomes very hard to manage and it becomes very hard to upgrade and refactoring the future. So by keeping it in a centralized place and making all the necessary requests parse through it. We're actually increasing the efficiency of our curried. Anyways now we're going to add in create listing into here. But before we do that, we'll, let's just move this one over a little bit hopefully. And now we're going to add this in into the listings service. So inside a listing service SLC, server route, we're going to add in a new route. And you'll see what I mean when I say that. What not going to do. And he sort of authentication inside of here. So what's it going to do straight away? Up top post, forward slash listings. Async equaled president S next here like that. And then if the description copy found or the body can't be found, or sorry, the title can't be found. And we do return next new era, and then we do invalid body like that. We do are try clause listing is equal to a white listing dot create. And then we've taken description requests, nobody builds description fights will request, I'll volleyball title. And then we return res.json within your listing. And if we get an arrow that we do return next eight, so we're kind of familiar with that now, Let's do this similar thing up here as well. So we put that out there, put this over here, and we press the Save and that will fall at that for us. And then inside of start server, we're going to add the necessary code from users service in order to handle errors. So just copy this and just put it right there. So now we can handle errors as well, and we can also add in new listings. So hopefully if this was working just fine. Notice how we don't have any authentication here. All the authentication is done inside of our mutation here, which is centralized. I think it works really well key, because remember that we used to actually doesn't have access to listing service. They only have access to the API Gateway, which then in turn accesses listing service. So that's a really important distinction is that you don't have to have that security every single level. You just have to have it where its most important. And then we have fetch all listings here. And we're going to add in a new one which is going to be Create listing. So static async Create listing tastes in our description and the title. And then what we do is we do body equals a white GFDL post and then our listings. So this URI and the fourth slash listings, so on a post to that. And then it's going to take an JSON description and title. And then we do a dot JSON and we return the body like so. So now that we do this essentially adds in on your listing for us. So hopefully this is working just fine and we can confirm that by going creating new one, refreshing real quick. And let's just add a new one, curly braces. And let's do mutation. Let's do creates listing, let's say description and also the title. So description, let's first thought without item title. And let's just say 16 inch MacBook Pro subscription with working in keyboard, well, something like that. And just return the ID and let's press play. And I see we have item number three. So if we actually look so over here, we have 16 inch MacBook Pro with working keyboard, and it shows up here as well. So now let's get this one hooked up and I make sure that works properly. Sorry, over here inside of classifieds, up inside of Add Listing. Instead of just console logging or going to run this mutation. So let's go up here. We've got using mutational ready. Let's use that directly inside of here. So constant square brackets creates listing is equal to use mutation, mutation like so. And then inside of here we do a white Create listing and we do variables, and we pass in the description and the title, and we're going to reset the form. Reset comes from Useful where the whi, which will basically clear all the values. And then we're going to have a look at ALS now. So we have cowboy hat will shrink bottle was 16 inch MacBook Pro, or let's just say for example, 109 AT XY CPU was the Intel IDE 9109 AT XY CPU. And let's just say disappointment for the description. Kind of a nerdy joke, but if you get it, you get it. And let's click Add Listing. Now this is gone and it's not showing up here. But if you refresh, it shows up. And the reason for that is the cause inside of listings, our data is fetched using this, and we don't know that we actually have to re-fetch that once Add Listing is done. So what we actually want to do is for a listing here we're going to add in function, so on add listing. And when we add an anew listing or going to re-fetch. So refreshed comes from the query here, which allows us to rerun the query. So on Add Listing outcomes from enlisting here, we're going to put that into here and rename it to push out listing as you know, I like to do. And then we're going to run that function when it finishes. Create listing here. So now we have these four items here. And let's just say, for example, this height or could be a legit tech mouse. Simple, cheap, and very usable, or something like that. And let's click Add Listing and that disappears and it shows up here on the page. Now, if we log out, we actually couldn't add anything to the form. So what we're gonna do is just add a little thing into addressing here, which is going to get the current session. So I'm inside of account details here we have this selector which we can just essentially copy, and I'll put here. So we have used selected here for this session. Let's go up here and grab this line for reactor redox. So now essentially if the session isn't set, I want you to do, if the session is not set, are going to do return a paragraph and then login to add listing like sorry. So now that we've done it, you see just shows login time listening here. And the great thing with using redox here in this situation is that when I click Login, this form automatically P is, and when I click logout, that automatically disappears. So now that I'm logged out, if I tried to add a new listing and I could play, you see we get a message which says not logged in. So that concludes it for this microservices application, I've showed you how to build essentially a classifieds outwards users react in the front end and also a bit of redox, bit of style components, bit of random stuff there with graph QL, I showed you an API Gateway which uses graph Q0 and kind of is the middleman between the classifieds up and the other stuff. In the back-end, we have a listing as micro service, which includes its own database using a SQL eyes. And we also have a user's Microsoft Office with its own database in SQL as well. So the next thing we're going to do is probably look at deploying this, probably on AWS or something similar to that, and looking at putting that out there. If there's anything else you guys want to see you, please let me know in the comments down below, I hope you guys have enjoyed this video series. This has been lucas with better Coding Academy and see you guys later.