Graphql with Apollo and Express: A Hands-On Approach | Aymen El Kani | Skillshare
Search

Playback Speed


1.0x


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

Graphql with Apollo and Express: A Hands-On Approach

teacher avatar Aymen El Kani, software engineer

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

    • 1.

      Apollo Graphql ad

      1:12

    • 2.

      Introduction to Graphql

      2:58

    • 3.

      working with Graphql Queries

      7:06

    • 4.

      Adding Mutations

      6:30

    • 5.

      Installing and Configuring Typescript

      4:42

    • 6.

      Basic Typescript

      14:22

    • 7.

      Advanced typescript

      15:28

    • 8.

      Creating The graphql Schema

      11:03

    • 9.

      Create Auth Resolver

      4:53

    • 10.

      generate Typescript files from schema

      8:22

    • 11.

      Setup our Apollo-express server

      6:53

    • 12.

      Run and Test our Api

      10:48

    • 13.

      install and configure typeorm

      4:14

    • 14.

      Create user entity

      7:02

    • 15.

      Create-user method | user.service

      7:54

    • 16.

      add app data source

      5:10

    • 17.

      Create signup resolver

      9:19

    • 18.

      Creating signin resolver

      12:13

    • 19.

      working with the graphql context

      13:17

    • 20.

      what is Docker

      1:36

    • 21.

      Install docker Linux

      2:17

    • 22.

      Images to containers

      5:58

    • 23.

      containers to images

      5:05

    • 24.

      running postgres database with docker

      8:08

    • 25.

      Test Graphql endpoint

      10:31

    • 26.

      from postgres container to image

      4:29

    • 27.

      Defining the room Schema

      5:56

    • 28.

      Auto generate and merge schemas

      13:00

    • 29.

      creating the room resolver

      4:41

    • 30.

      merge resolvers

      5:09

    • 31.

      creating the room entity

      7:33

    • 32.

      creating and updating rooms

      9:24

    • 33.

      CreateRoom resolver 1/2

      8:22

    • 34.

      CreateRoom resolver 2/2

      4:33

    • 35.

      Creating getRooms resolver

      3:55

    • 36.

      Test graphql enpoint

      7:33

    • 37.

      Implementing validation with class validator

      2:27

    • 38.

      Catch validation errors

      6:50

    • 39.

      why we should use ScoketIo

      1:14

    • 40.

      Join rooms with socketIo

      7:39

    • 41.

      Emit messages to a specific room

      2:41

    • 42.

      Testing socket Io server

      4:15

    • 43.

      Database migration with typeorm

      11:15

  • --
  • 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.

11

Students

--

Projects

About This Class

Welcome to the GraphQL with Apollo and Express course on Skillshare! In this class, you will learn how to use Apollo GraphQL with Express and TypeScript to build powerful and scalable web applications.

GraphQL is a popular query language for APIs that enables you to request only the data you need, which makes it a great choice for building modern web applications. Apollo is a GraphQL implementation that provides tools to help you build GraphQL APIs and client applications. Express is a fast and flexible web application framework for Node.js, which is widely used in building APIs and web services. TypeScript is a typed superset of JavaScript that helps you write safer and more reliable code.

Throughout this course, you will learn how to set up an Express server with TypeScript and integrate it with Apollo GraphQL. You will also learn how to define GraphQL schema, resolvers, and data sources, and how to use Apollo tools to fetch and cache data from a GraphQL API.

Some of the topics covered in this course include:

  • Real-time communication with SocketIO: You will learn how to use SocketIO to implement real-time communication between the server and the client.
  • Database integration with Postgres: You will learn how to integrate a PostgreSQL database with your backend using TypeORM, a popular Object-Relational Mapping (ORM) library, and how to perform database migrations.
  • Containerization with Docker: You will learn how to use Docker to containerize your application and simplify deployment.
  • Authentication with JWT: You will learn how to implement authentication using JSON Web Tokens (JWT) and how to secure your GraphQL API endpoints.
  • TypeScript: You will learn how to use TypeScript to write type-safe code and improve the reliability and maintainability of your GraphQL API.

By the end of this course, you will have a solid understanding of how to use Apollo GraphQL with Express and TypeScript to build powerful and flexible APIs for your web applications. You will also have hands-on experience with advanced topics such as real-time communication, database integration, containerization, and authentication.

You will be able to share your project with other students on Skillshare by uploading it to the project gallery, where you can showcase your skills and get feedback from other learners.

Whether you are a beginner or an experienced developer, this course will provide you with the skills and knowledge you need to take your GraphQL development to the next level. So, join us and start building advanced GraphQL applications today!

Meet Your Teacher

Teacher Profile Image

Aymen El Kani

software engineer

Teacher
Level: All Levels

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. Apollo Graphql ad: Are you tired of traditional rest APIs and want to learn the latest and greatest and RPA development look no further than our GraphQL course. In this course, you will learn everything you need to know to get started with Graff girls, starting with the basics of building a Graciela BI with Express. But we don't stop there. We'll dive deeper into using a border server with TypeScript and express, working with type RM and using Postgres database with docker. Our course isn't meant to be a full graph care costs, but it will teach you all the essentials. You will learn about Graff girls, halo types, queries, mutations, schemas, and how to merge schemas and resolvers with a photograph girl will also learn TypeScript and cover socket IO and a database migration with diaper. And by the end of the course, you'll be able to confidently build your own GraphQL API and work with some of the latest and most powerful tools in the industry. So what are you waiting for then row now for our golf Gail course and take your API development skills to the next level. 2. Introduction to Graphql: Hello and welcome to this first lesson on graph gear. This lesson we'll be introducing Dr. Gale, discussing queries and mutations and explaining what a schema is. So what is GraphQL? Graphql is a query language and runtime for APIs developed by Facebook. It allows clients to ask for exactly what they need and nothing more. Make it a powerful alternative to traditional rest APIs. One of the key features of graph Gil is it's Query Language. The query language allows clients to specify exactly what data they need, including nested data structures and retrieve it all in a single request. This makes it very efficient for clients to retrieve data from the server. As they don't need to make multiple requests to get all the data they need. Let's talk a little bit more about queries. In golf. Gayo, a query requests for data. It specifies the field that the client wants to retrieve, as well as any arguments that are required. Here's an example of a simple query in GraphQL. In this query, we're asking for the name and email fields for the user with an ID of 123, the response from the server may look something like this. Now let's move on to mutations. Mutations in GraphQL are used to modify data on the server. They allow clients to send data to the server to create, update or delete resources. Here's an example of a simple mutation in GraphQL. In this mutation we're creating a new user with the name Jane Doe and email Jane Doe at example.com. The response from the server may look something like this. Finally, let's talk about schemas in GraphQL. Schema is a contract between the client and the server. It defines the types of data that can be queried and mutated, as well as the relationships between those types. The schema is usually defined using the GraphQL schema definition language, or SDL for short. Here's an example of a simple schema in GraphQL schema definition language. In this schema, we have a query type with a user field that takes an argument and returns a user object. We also haven't mutation type with the create user field that takes a create user input object and return a user object. Binary. We have a user type with ID, name, and email fields. That's it for this introduction to graph Gail, we've covered what Garcia is, our query is and mutations work in what the schema is. In the next lesson, we're going to dive into building GraphQL APIs. 3. working with Graphql Queries: Hello and welcome back to our GraphQL course. In our previous video, we covered the basics of GraphQL, including queries, mutations, and schemas. In this video, we will be building a simple graph gala PI will express. Specifically, we will be using Express to handle our GraphQL requests and responses. And we will be leveraging the power of Graff girl to retrieve data from a data source. By the end of this video, you will have a solid understanding of how to create the GraphQL API with Express. And you will be able to apply these concepts to your own projects. So without further ado, let's dive in and start building our graph. Gala PI with Express. I have prepared the project for you to follow along within this video, you can download it from the resources section. I have included an index.js file in the project. This file contains the code necessary to start listening for connections with Express. In addition to that, you'll find a package.json file with three dependencies. Express, express, Dutch, Graff, girl, and graph. Here. These are the main tools we will be using to build our GraphQL API I would express. Additionally, node money is also installed and configured in the project. This tool automatically restart our server when changes are made to the code, which will save us a lot of time and make the development process smoother. Now, before we start working on the project, it's important to make sure that all the necessary dependencies are installed. To install these dependencies simply navigate to the project directory in your terminal and run the command npm install. This will install all the necessary packages for our project. Once the installation is complete, we can move on to building our graph, get RPI with Express. Now in a graph Gil project, the first thing you need to do is defining the schema, which is the foundation of a graph. Get RPI defining its types and fields. We need to start with it before anything else to ensure our APIs clear, self documented, flexible, and extensible. To build the schema, we need to import the function with the name build schema from GraphQL package. Then create a schema constant and use the build schema function by opening two parentheses and pass in a template string. Here we're going to define our first query by adding the keyword type like this, and add the named query. Then open two curly braces. And inside here we can define our queries. So I'm going to define a simple query hello. Then we need to define the return type of this query. To do that, add a colon, then specify the return type. Now our case, the hello query is going to return a string, make sure to add an uppercase S. Their types are used to define the structure of the data, including scalar types such as strings, integers and booleans, and object types, which consists of a collection of fields. Now in order to handle requests coming to the hello query, we need to define a root resolver. The root resolvable is responsible for fetching the data requested in the query or mutation and return it to the client in the correct shape defined by the schema. Essentially, the root resolver acts as a bridge between the API and its data sources, making it a critical component of any graph girl or PI. Now to define this route resolver, let's create a route constant like so and set its value to an object. And this object, we need to add all our queries with the same name written in the schema. So here I'm going to add a hello property of representing the hello query and set its value to an arrow function. By the way, every query or mutation should be a function. Right now, here let's just return a Hello World message. Now, we need to define a Raphael and buoyant in our API. We can do that using Express. So it's similar to defining middlewares. Said the endpoint path to slash Graff girl. And for the request handler, we will use another function named Dr. Gil HTTP. We can import it from the package express, that is GraphQL. Now inside here, we're going to use the GraphQL HTTP function like so. An object as an argument. The subject will hold our schema. You can set it like this or just the name schema and JavaScript, we'll know that we're referring to the constant schema. Second property is the root value property, which will hold our root resolver. And the last property is Graffiti Girl, which is a web-based graphical, interactive GraphQL client that allows users to interact with a GraphQL RPI by executing queries and mutations and visualizing the results. When set to true in the express GraphQL middleware configuration, the graphical option enables the graphical interface for testing and exploring our GraphQL API. With that being said, let's save our file and open the terminal and run this document. Then let's open the browser and navigate to localhost 4,000, such Scarf Girl, where you will find the graphical interface. Here we can write our queries and even check the documentation of our gov gala PR. Here you will find our query and inside it the hello query, which returns a string. If you click on it, you will see the definition of the string scalar. Now, to fetch the hello query from this server, we have to define the query like so. And then mentioned the whole query inside it. Once you have done that, click on the Play button to send the query to the server. If everything is set up correctly, you should see the result received from the queries over on the right side of your client. Great work. In the next lesson, we'll continue to explore that scale by learning about mutations. 4. Adding Mutations: Now let's add a mutation to our API. So GraphQL mutation is a way to modify data on the server using the GraphQL API. It allows clients to send the request to the server to create, update or delete data. Mutations are defined in the GraphQL schema and can be executed by sending a graffiti on mutation query to the server. So let's define the mutation by going to the schema and add a new type. And I met mutation with a capital M. And let's assume that we want the client to add products to our server side here. That's added mutation handle with the name add product. This handler will accept a name as an argument of type string, again with capital S and a price of type int, which refers to an integer. So in growth Gil, the type int represents a sine 32 byte numeric integer. It is used to define fields that return or accept integer values in graph G 0 schema. Then type can be used to enforce type validation on GraphQL queries and mutations, ensuring that only valid integer values are provided as an arguments. We can define this type as required by adding an exclamation mark in front of it. We can do the same thing for the name argument. Alright, now we need to define a return type for this mutation. So GraphQL mutation needs a return type to specify the shape of the data that will be returned from the server after the mutation is executed. So to do that, or the colon here and add an array, because we want to return an array of product objects. And to define the type of this product object, Let's go here and add another type and name it product like. So. This product will contain a name of type string with the exclamation mark to make it required. And then hit Enter to go to the next line and make sure not to add a comma here because it's not allowed in drift gill schemas. The second property is the price of type integer. We can also make the return type requires so we can prevent getting a null as a result. We can do that by adding exclamation mark in front of the product and the array itself. We can also change the way we listed our mutation arguments and replace them with one argument and name it input and set its type to add by direct input. This is a custom type, not a built-in type of GraphQL. Therefore, we need to define it ourselves. We refer to it as input type. So in GraphQL, the input type is special type used for arguments in mutations and queries, is used to define the shape of data that can be accepted as input by field. The input type can contain scalar types like string into or Boolean, as well as other input types allowing for complex nested structures. Input types are similar to regular types and graph care, but they cannot be used as return type of a field to define the Add Product input type. Go ahead here and use the input keyword and add the same name. And inside it we will add the same arguments, name of type string and price of type int. Now let's save this file and return to the graphical interface. Here we can add our mutation query. Start by adding mutation in opening two curly braces are the braces and the add product mutation. Next, add an input argument inside an object, the name of the product that says SPC. Then be careful with the price input as entering numbers as a string, one to work since we set the type to integer, instead enter the numbers directly, like so. The return object, we want to get the name. And the Bryce. If you hit the play button, it didn't work. And that's because we didn't define the add product resolvable in the root object. That's very quick. Add a comma here and create the ad product and resolve or legs. So this resolvable will accept an input argument. But not directly like this, because the input argument exists inside the primary object argument named args. So we can get access to the input argument like so. Then this resolver should return an array of objects. So that's hardcoded and add an array with one object with two properties. Name, we can get the name from the input like so. And price from input dot price. Then let's save and test again. And there we have it. Our array with one product object contains the name and the price. We can tell the server to only return objects with the name property by removing the price field from here. Hit play. And as you can see, we got an array of object containing only the name property. Great, Now that you have a basic understanding of GraphQL, let's take the next step to level up your experience by learning how to use a portal graph gail with Express and TypeScript. Apollo GraphQL is a powerful tool that provides features such as caching, error handling, and schemas stitching, making it easier to build scalable GraphQL API ice by combining a photograph Gil where they express and TypeScript, you will have the ability to build highly maintainable and type-safe GraphQL APIs. So get ready to dive into the award of a photograph Gill, and let's take your graph girls skills to the next level. 5. Installing and Configuring Typescript: Now before we get into the TypeScript syntax, we first need to install the TypeScript compiler to begin had an oval or TypeScript lang.org slash download URL. And here you will find a number of ways to bring the TypeScript compiler into your project depending on what tools you may be using. In this course. However, I'm going to be relying on the NPM environment, since that's what I expect the majority of JavaScript applications are using these days. Now, regardless of where or how you install TypeScript, if you don't already have node, you will have to install it by heading over no js.org and then follow the instructions to install the latest FTC. Now, if you've got npm installed in your system, Let's go back to the download page of TypeScript and copy this line here. Then we're going to run it said our project and inside our terminal. So make sure to create a new directory here, open VS code and run npm install TypeScript. Does that save that stiff if you want to install TypeScript inside your project and only inside your project. But it means that with the desk does saved as div option here, you will only be able to use TypeScript inside this project. You can do that by, for me, I want to use TypeScript globally inside by system. So I'm going to add the flag dash g for global and then run npm install. And you may need to use sudo to run this command as an admin. And if you're using Windows, you have to open a new admin console. Now, I already have TypeScript and stored globally inside my system. So I'm not going to run this command. And to make sure that you have installed TypeScript successfully inside your system, you can run TSE, that's V, and you will get the version of TypeScript. I'm currently on version 443. And it doesn't matter if you have a higher version of TypeScript than mine. Because all the TypeScript centers that we're going to use in this course is going to be applicable with any higher version of TypeScript. Now, in order to use the TypeScript syntax and self-doubt project, we need to add some TypeScript configurations. We can do that automatically using the TSC command line, then dies in it. And as you can see here, we have a new file inside our project and named ts config dot json. So let's open it. And as you can see, TypeScript offers a lot of options here. Lot of them are commented because we're not going to use them. Now the first uncommitted option here is the target, which represents the sigma script version. In this course, we're going to use my script six. And if you scroll down a little bit, you will find the module property set to comment. Yes. This means that the modules and the compile dot js files. We'll use the common tier syntax because almost all the browsers have support for this module. But if you want your files to be compiled with modern JavaScript syntax, you can try to use years 2015, like this, ES 2015. But as I said, we're going to use coming to us in this project. Now under this, we have the root property which specify the location of the files that uses the TypeScript syntax. So let's end commented and keep it pointing to the root of this project. Now let's scroll down to the out their property, which specifies the location of the compiled files. So let's increment it. And we want all our files are our compiled files to be located inside the dist folder. We don't need to create this folder manually inside our project because TypeScript will do that for us. Okay, Now this is all we need to get started. So let's save the ts config file and start using TypeScript syntax in the next video. 6. Basic Typescript: It's time to start learning about TypeScript syntax. And for that, we need a new file inside our project. So go ahead and create a new file and name it main dot ts for TypeScript. Then here we're going to start with declaring a variable and name it firstName, and set it to John. Now we just wrote normal JavaScript. But if I hovered over firstName, I will find that firstName is of type string. Now, we can find the same thing with pure JavaScript, but let's try to set this variable to five. Now, we got an error. If you hover over that error, you'll find that TypeScript is complaining about the type or the assign a value to this variable. It says type number is not assignable to type string because five here is a number and John is a string. So it's like TypeScript is saying that if you assign this variable from the beginning to a string, you have to keep it like that. This is why TypeScript is helpful because it prevents small bugs like this from appearing inside our project. Now, we want the firstname variable to be always of type string. But let's imagine that another developer comes in and he changed the value of the firstname variable to a number, let's say like ten. Now the IRS has disappeared from the second line or the third line here. But we have introduced another buck goes here. Firstname variable is no longer of type string, but it's of type number. Now, you might ask yourself why TypeScript didn't alert us that we have made a mistake? Well, it's obvious because we didn't tell her to do that. So in order to tell TypeScript to only accept strings for this variable, we have to add a colon and then string. Now you can see that we got two errors. Well, it's the same error, but in two different places. It has the same message as before. Number is not assignable to type string the same message. We can find it here. To fix this, we can just remove the ten from here and replace it with a string. John. We can actually remove this because it's that variable and assign this variable in the third line like this. And here we can see that the IRS has disappeared. But let's just keep it in one line. So I'm going to take this again and I'll move the firstName from here and assign this to John. Now, if you want to declare a number instead of string, we can create another variable, name and age, set the type to number, and then sign into any number, going to choose 22. And now you know that if you do this, you will get an error saying that type string is not assignable to type number. Now we don't have only strings and numbers, we also have objects. So let's declare another lead variable. Name it LPG for object, and then set it to an object with the property first name set to chart. Now in the next line, let's try to reassign the firstName property to a number and see what's going to happen. So object firstName equals five. Now here you can see that we have an error from TypeScript saying type number is not assignable to type string. And that's expectable because declaring object properties is similar to declaring normal variables. And same thing if we try to assign the object to the firstname variable, we will get the same error. And this time, time type string is not assignable to type than the object we assigned to the variable from the beginning. Now, let's remove this and assign the variable type to an object. Now, you can see that we didn't get any errors. But I want to make it clear for the eyes that this arbitrary variable is an object that contains a firstName property of type string. We can do that by removing the object from here, replace it with two curly braces. And inside here are the first name property and set it to type strain. Now let's say that I want to add a new property to this subject, e.g. H. We will get an error saying that type object with property firstName, string, and age number. It's not assignable to the object that has only firstName property of type string. Now this is going to be very helpful if we want our objects to only contain a very specific properties. And of course, if we want to add the age property, which is a number, we can come here and then add age of type number, and the arrow will disappear. Now after strings, numbers, and objects, let's see how we can define functions with TypeScript. So let's declare a new function and name it. Create user. This function will accept two arguments. First one is the first name, second one is the age. Now you can see here we have two errors. Firstname or the parameter firstName implicitly has an any type. Now functions arguments are also variables. And JavaScripts set the type of these arguments by default to the type any. But TypeScript doesn't allow that, so we need to add types for these arguments. So for the FirstName, addString, and for the age is a number. Now let's return something from this function. Return firstName plus the h. You can see that we didn't get any errors because even TypeScript know that we want to convert the age to a string and then concatenated with the firstName variable. Now, if you change the plus sign with a minus sign, you would get an error. Because TypeScript knows that performing a subtraction operation between a string and a number, it's not logical. So let's remove all of this and replace it with a literal string. And inside it we will have FirstName, then add the firstname variable, and then age, the age variable. Create another variable and name it stl string. And then let's execute the create user function. Now you can see here that we need two arguments. So that's first name to John and the age to 22. Now, if you hover over the STR variable, you'll find it of type string. We can specify the return type of a function as we can do it for a variable using a colon here, and then add type string. Now, let's say I want to return an object from this. Thanks for that. Going to change this with object. And we will get an error saying that type string is not assignable to type object, but the Variable STR is of type object. Now, let's fix this error by moving this string and replace it with an object. The other is gone. But let's say I want to return this object with an age property set to the aids argument. If I want to use the return value of the current user function, which is an object that's supposed to contain an age property. We will get an error saying that property age does not exist in type object. Can fix that by removing this, add an object and the A's property with the type number. Now, if you hover over h, you'll see that it does exist and it has type number. Let's add also the firstName inside this object and set it equal to firstname argument. Here we have an error because we have to add the firstName property to the return type of this function. So firstName of type string. Alright? Now let's say that if we have an aids higher than 20, we're going to reject that aids and only return the first name. So here, let's add an if statement and check that if the age is equal or bigger than. 20. If so, we're going to return only an object with the firstName property. Now, TypeScript doesn't want to let me return this object without the age property. That's because we told her that this function is going to return an object with only the age property of type number and the firstName property of type string. We can fix this by making the age property as not required by adding a question mark here. Now the error is gone. And if you hover over aids, property will find that h is of type number or undefined. Now, you can do the same thing for the age argument dissatisfaction, but only if this argument is the last one in the arguments next. Now, if we add the question mark here, we will get an error saying that object is possibly undefined. Now, you may wondering why we have upset here, not number. Well, that's because in JavaScript, everything is a, an object, even functions. But you can find the type of the age argument as number or undefined. If we change the location of this argument and put it from the beginning here, you would get another error. Saying that a required parameter cannot follow an optional parameter. So if you add a question mark here, the arrow disappeared from the arguments list, but you will get many errors in the function and outside the function where we executed it. Now we don't want this. We want to change everything as it was. So let me remove this from here, put it there, and remove the question mark from the H argument. Now, let's say that we want this function to accept the aids as a number or as a string. We can do that by adding one vertical bar and adding the string type. Of course we have to do the same thing for the return type of this function. Let me close this to have more space and add a bar here with this string type. Now the age here is of type, string, number or undefined. We can do the same thing for a variable, e.g. for the FirstName here, Let's add either a string or a number. Or let's do it for the age. So here we have a number. Let's add a string. Alright? Now we can assign the age variable either to a number or to a string. Like this. 7. Advanced typescript: Now, going back to the current user function, imagine if we have more properties inside this object with more complex types. In that case, it's not going to be convenient to have a big object in front of this function. And to fix this, TypeScript has introduced something called interfaces. An interface is also an object, but you can only use it as a reference to a type. This is how we can declare an interface using the interface keyword and then the name of the interface. And I'm going to choose user. And as I said, we're going to create an object, but without any equal sign or a column. You can think of it as a class. Now, let's take all of this, the age and the firstName. Cut it from there, remove the object, remove the colon, and paste them here inside this interface. Let's adjust the code a little bit. You can hear use a comma, but also you can use a semicolon or you can just remove anything from there. But I want to use semi-colons because it looks more organized in this way. Now, we can use the user interface like any other type. Here, the colon and then the user interface. And if you hover over aids, you'll find that the age still have the type string, number and undefined. Put in mind that interfaces only refer to a type of an object. So if you remove the curly braces from here and just leave the aids, you'll find. You'll get an error saying that string or number is not assignable type user because the user has, first of all, has two properties and user is an object. And do the changes. And let's create another function and name it login. This function is going to accept one argument and it's going to have the name login ox. It's going to be of type login. And of course we're going to define an interface login. So let me copy this name. Here is interface and define the login interface. So in order to, for a user to login, you will need an email of type string and the password of type string as well. Actually, I want to have control of the password type while using the login interface inside the login function. To do that, we can change the center face to be generic by adding two angle brackets like this. And then you can think of this interface now as a function that will accept an argument as a type. And we can choose the name of the argument. I'm going to choose PWD for password, and I'm going to assign that type for the password. Now, here, if you hover over login, you will find that generic type login requires one type argument. As I said, functions has arguments. So for the generic type is the same concept. Now here we can define that argument by adding a angled brackets and the type of the password inside it as a string. Now in satisfaction, let's very quick check if the login args dot email equals e.g. he made and the login args dot password equals e.g. password. That case, we're going to return true. So the user is authenticated. Now here, else, we're going to return False. Going to set the type of the return value of this function to body. And this is a new type that we can use. And it doesn't need a definition because they boolean is just either a true. False. Now, going back to the login interface, we can use another variable that only refers to a type and holds the password type for us. And because the password is not an object, we cannot use the interface keyword. We only can use the type alias and then name the type to be password type. And then we can add these string to that type. So here string. Then we can use the password type inside the login interface. If you hover over it, you will find that password type is a string. You can add here either a string or a number. And you can add any type you want. But passwords can only be strings or numbers. We can also use the type alias to add a type to a variable or to a return value of a function. So here I'm going to add type login, result equals volume and make sure it's uppercase. And here for the body, and we can use a lowercase or an uppercase. It's the same thing. Let's change this to login results. Now, imagine that we have an async function. We're going to use the async keyword to define that. In this case, we got an error saying that the return type of an async function or method must be the global promise generic with the T argument type. And then he says, Did you mean to write this generic type? Now, if you know JavaScript, you will know that an async function will return a promise. And this is how we can define a promise type with TypeScript. So let's change the login result to be a promise because this function is going to return a promise. And then the generic or the argument of this generic type represents the real return type of this function, or in another word, the resulted value, or the type of the resolve that value. So here we're going to resolve a Boolean. And you can see that the error is gone. Now, let's say that if we authenticated the user, we will send an object instead of true. And this object will contain a username property, said to John again, and another property status set to active. So we have an active user inside our database. Of course we don't have database here, but just imagine that we have one. Now of course we're going to get an error. And to fix that, let's add an interface here and name it, number, and cite it. We will have the username property of type string and the status property set to string as well. And here we will get a promise that will resolve either a Boolean or a number. So have made a mistake here. Right now the Earth has disappeared and we can return either a force or an object. Now about the status property, we can only return three status, the active status, inactive status, and the new status. So here you have to always return one of these strings. But if I wrote active like this, in this case, I made a typo. But TypeScript didn't say anything. Because TypeScript doesn't know about these strings only cares about the type of the status property being said toString. And as you can see here, I already made a typo. So how we can prevent these type of errors or mistakes? Well, it's very simple. We have to declare an enum type. So here, Use the NM ideas and then name this enum type member status. And it's going to be an object, but it's not going to refer to an object. I will tell you how we can use it in just a second. Now here we can define these three types by adding active and inactive. And then the new status. Now we have to replace this string here with the members status enum. And for that, we have to use numbers status enum also to 2s to select the active status. That active. You can see here that VSCode has the three types here as a success since this is very helpful to speed up the development process. Now let's choose active. And if you hover over it, you will find that members status that active equals zero. Now, you can refer to the active status as a string by adding equal. Then active. Same thing for the inactive. Here, string, copy inactive. And for the new also knew. Now, if you hover over active, you'll find it active equal active as a string. Now inside the member interface, we can only accept one of these properties. So now we will not be afraid from misspelling one of them. Now, let's save this file and let's open the terminal and try to compile. We can do that easily by using the TSC command and just hit Enter. The TSC command is going to check if we have any errors or any type script errors. And then if everything is okay, we will have a dist folder containing the main.js file. If you open it, you will find here a lot of code. But all the types from before, from the main.js file has disappeared and we only have pure JavaScript. You can see how TypeScript compile the enum type. And did all of this for us. Skulls, the main dot, dot js file. And now you can say that you learned pretty much everything about TypeScript. Before finishing the video, let me very quickly show you how you can use the login method. So here, take the non-game and pass the object with the email set to email, password, to password. And then because this is an async function, we're going to use then method to get the result. And then we're going to check if the status is active or not. And to do that, we're going to create an if statement and check first if the result is an instance of the class Boolean. And by the way, the Boolean with the uppercase B is glass. And it is a whirlpool for the type Boolean with the lowercase b. So this type here refers only to a true or false. But the Boolean with uppercase B refers to a class that contain the type Boolean. So I'm going to do this. If it is an instance of Boolean, then return. Otherwise take the result that status. Check. If this is, this status is equal to login or a member. Status active. If so, we're going to return true. Or maybe console log. User is active. User is active. Now if you want to use body and with lowercase, change this and you can check for the type of Boolean with type of keyword and then result equals to ensure its volume. And if you want to do a check like this with the exclamation mark, you can remove the Boolean type from here and replace it with null. And instead of returning false, going to return null. This is better. And you can see that null also is a type. Now you will find this file attached to this video with other TypeScript resources. So make sure to download them and learn more about TypeScript in your own. 8. Creating The graphql Schema: I'm inside VSCode and here I have two fives, the ts config file and the bank has the JSON file. Now for the ts config file, we have some new options here, like the library is set to yes, 2021. And the module resolution also set to note with the types also set to note. Now, for the strict property initialization option, make sure it's set to false or you can just remove it from your ts config file. Now, close this and by the way, I will add a zip file to this video so you can find it in the resources and downloads. Now we're going to add some packages from MPM. So here I have the terminal from the VS Code. You can open it by clicking here under terminal and click on new terminal. So here I'm going to install new packages like the express with the types for express. And we're going to work with Apollo server with express. So I'm going to install a polo Server Express. And of course we need GraphQL and the types for GraphQL. So here at types slash graph gear. And just in case I'm going to install the types for note. Now let's run this command and install all of these packages. Alright, so now let me clear this terminal and inside the root directory, let's create a new source folder. And inside here we will have a main.js file and a module dot txt file. And for now we're not going to touch these two files because we have to create the GraphQL schema first. And for that, make sure you are again inside the root directory and create new file and name it schema. That Raphael. Alright, now here it's GraphQL schema consists of mutations and queries. We use mutations when we want to change data inside the database. And we use queries when we want to get data from the database. You can think of them as posts in requests if we were using a RESTful API. With that being said, let's define our first mutation. And to do that, we have to use the type keyword and then write mutation. And inside here we will have the sign-up mutation. So right, sign up and sign up. It's going to accept the user input. So here we're going to write input as a argument for this method. And we have to define the type of this input so that when we use this mutation with our API, we will know which arguments are required and which are not. And define such type. We have to use the input keyword here, right? Input, and then name this input type Sign-up input here, and make sure you have an uppercase S here for us, for its type or it's sharp input and it's not required, but it's a common thing to do with GraphQL. So here, sign-up input side here we're going to define the sign-up arguments. And by the way, you might not have the syntax of GraphQL colored like this. Because if you want that, you need to install a extension for GraphQL. So head over extension section here and search for GraphQL extension. I have it already installed here. So make sure to install the same extension. And then you may, you may have to create a config file after installing this packet. So scroll down here and you have to create a dot GraphQL fc dot YAML file and copy these two lines and paste them inside your project. And you can see here that this config file, our start targeting the older GraphQL files inside our source folder. In our case, we don't need that yet, but in the future, we're going to have multiple GraphQL files. So you may need to also copy this line and paste it inside the config file. And I will also do that in my side. Just to make sure that we're not going to forget this in the future. So go back to our project and in the root directory, create a new file and name it dot GraphQL LRC than the GMO. And here, paste that code here and close it. And then you will have the same styles for GraphQL. And not only styles, but also autocomplete. Yeah. That's why I recommend you to install this extension and use it. Whenever you create a graph kill schema just to prevent typos and unnecessary debugging if you made any mistakes here. Yeah. So just to make sure I have the GraphQL inside the root directory in here, Let's continue with the sign-up input. So to create a new user, we need an email of type string. And make sure you have an uppercase S here. And also make sure you don't have any semi-colons or comes here. And now define also the password of type string. And also we need a first-name of type string as well, and the last name of type string. And now let's use this type here for the sign-up input. And as you can see here, it's, it's similar to the TypeScript when it comes to defining and using types. Yeah. So you might not have any difficulties in understanding the GraphQL syntax, right? So now let's define the return type of the signup mutation. Now, whenever we sign off, we will get back the user, the user document, and the JWT token. So let's define that. And this time we have to use the type keyword, because the input keyword is only used when we want to define the inputs for mutations or queries. And the type is used to define mostly the return types of mutations and the queries. Now here define a type and name it earth response. And here we will have a user. And then this one is going to be of type user. And we will define this in just a second. And here we need also the JWT token of type string. Now, on top of all of these are going to define the user typed in. We have to define the ID as well for the user, because when we start using the database, we're going to return the ID. Yeah, so we have to define that otherwise will not, will not get the id from the GraphQL schema when we request for the user document. So the ID here. And because we're using the type rep, we will use diaper around. With Postgres. The id is going to be of type number. But in GraphQL, we cannot use, we don't have a number type like this, but we have an N-type. Yeah. And just to make sure that we're going to get the ID every time when we request for the user, we will add an exclamation mark here. And with this symbol, we can define a required field inside our schema. Now, the user also have all of these here. So let me copy this and paste them here. And that's it. Now let's use the user type here or the author response type. So here, off balance, and then save. Now we have to make sure that the sign-up input also required to prevent getting undefined inputs. And the same for the earth response. Yeah, and now we have to define our schema. And to do that, I'm going to use the schema keyword. Then cite this. We're going to define the mutation. And it's going to be of type mutation. Then when we create the query, the queries, we can come here and create query like this and then give it the query type. But for now we only have mutation and make sure that at least you have either a mutation or query here or both of them. Otherwise, you are the GraphQL gateway will not resolve. Now, let's save this and create a resolver that will handle these sign-up logic. 9. Create Auth Resolver: Now that we have our GraphQL schema defined, Let's create a resolver. And because we defined a signup mutation that is related to authentication, we're going to create a folder inside the source folder. And inside it, we're going to have a resolvers file. And here we're going to define the object that will contain our mutations and queries logic. So create a new constant and name it as resolvers. And it's going to be an object with a mutation property. And inside that, we're going to define the sign-up method. And of course they sign up method is an async method. Now it's GraphQL resolvers going to have a parent argument and an object containing the input value and also an argument or a constant contexts argument. We're going to explain the context argument when we define the main and the module. But for now, we know that we're going to get an input from our sign-up resolver. And all the arguments inside the sign-up input is going to be defined here. For the parent argument, we're going to have the return value of the parent resolver. And that's only when we have a nested resolvers. But in our project we're not going to use that. But I can, I can show you an example. So imagine if we wanted to find a signup mutation, but not in this way. We will create another type and name it, sign up. And here we will have like a with email. And this method will return the set of user. And we will also have, like with Google, sign up with Google. And this one will return a token of type string. So to use this, we can also add the input to the width method here and then remove these parent disease. And here the signup mutation is you're going to be of type sign up. And with this, we have defined a nested resolvers inside the author resolvers here, we have to define the signup mutation like this. And we will only return like an empty object. And then outside the mutation object, we're going to have a sign-up type. So create a sign-up property here. And inside it, we're going to define the width e-mail and with Google methods. Yeah, So here with email and then it's going to be a method. Of course it's async. But now we can get the parent. Yeah. And in our case, this example, the parent is going to be an empty object, but this is how we can get the nested result of how to build nested resolvers and use the parent argument. But like I said, we were not going to use this because it's over killing. In my opinion. We just want a simple resolvers. Let's return everything like before and remove the sign-up type. Alright. Now, inside the Earth resolvers, you can see here that we have a type script errors saying that all of these arguments here doesn't have types and that's not allowed with TypeScript, as you know. In the next video, we're going to learn how to automatically generate TypeScript types from the schema dot GraphQL file. 10. generate Typescript files from schema: Now, in order to generate automatically type struck types from our GraphQL schema, we need to install some new packages. So head over your terminal and run npm install dash, uppercase D for dev dependency. And then Right the bucket name, GraphQL, that's cogent slash CLI. And also we need some other plug-ins for this package. So again, co-gen. And we need the TypeScript plug-in. And also again, GraphQL slash or a dash co-gen slash TypeScript resolvers. And run this command. And now inside our package.json file, we're going to create another command here and name it generate. And we're going to use the GraphQL coaching. And then we're going to specify a config file and name it cogen dot YAML. Of course we don't have this file yet. So let's created inside the root directory and save this config file. We're going to specify the schema path. In our case it's inside the root directory, then Schema dot GraphQL, and then under generates. We're going to save our generated types inside the source folder. And then side generated folder. And then say the resolvers types dot txt file. And now we have to specify the plugins. So plugins, we installed the TypeScript plugin, and we installed also the TypeScript resolvers. And now we have to add some configurations related to TypeScript. So I'd use index signature to true. And this option here allows us to generate dynamic TypeScript types. Now add a colon here and save this file and go back to the package.json file and save it as well. Then let's run this command from the terminal npm, run, generate, and wait for it. All right, We have successfully generated our divs inside the resolvers types. You can see that we have our user, our author response here in our mutation signup input types. Yeah, user is here and everything is declared. Of course there is a lot of configurations and other types related to graph girl. Yeah, so let's close this file now and go back to the author resolvers and import resolvers from the generated resolvers. Let's close this file and let's go back here. And so they all three solvers and use these enumerated types that we have to import from source or from the generated folder. And from resolvers types file, we're going to import resolvers. And we have to implement that type here. And now we can see that all the TypeScript errors has disappeared. Because now TypeScript knows that the mutation property has a sign-up method. In the sign-up method is a GraphQL resolvers and its draft, your resolver has a parent has an input and a context. And now if you write input, then you will get suggestions for the from the sign-up input type. Now, let's continue building the sign-up method. And I'm only going to return and dummy data here. So we need to return an ID. Or actually you have to return a user property. And inside it, we will have the user ID and it's of type number. Let's add ID1 and the e-mail. Then let's just add a random email here and the return the first name and the last name. This is just for testing because we should start working on the main and the module files and test our results. Right now, let's add the last name. It's going to be just user and safe. So actually we have to use the input here. We have to return back the input coming from the user, from the client. So I'm going to spread all the properties inside the input argument. And you can see that we don't have any errors from TypeScript. So it means that we're returning the same properties that exist to cite the user. So you can see that side, the schema dot GraphQL, we have email password, FirstName, LastName is that the user type and the same inside the sign-up inputs. That's why we don't have any errors. Now, we still need to return the JWT token. And this one is going to be just a random string. Now, if you noticed, we didn't get any errors when we was missing the JWT token. Yeah. And that's because Saturday schema dot GraphQL, we didn't add an exclamation mark here. So we have to add this or to make these two properties required and save this file. And now we have to run again the generate command so we can make sure that the author resolvers. We are returning the JWT token with the user property. So here we have generated the schema, and here we go we have a TypeScript error saying that we are missing the DWT. So here if we added the DWT property, the Earth will disappear. And for now we're going to just send some dummy data. Then after we are finished the main and the module files, we're going to get back here and finish all the mutations and queries. And that's because we still need to connect to a database and create the user entity inside that database. So with that said, the next video, we're going to start working on the module and the main files. 11. Setup our Apollo-express server: Now inside the module, the ts file, we're going to set up our Apollo server to work with our GraphQL schema. And the author is solvers. So let's start by importing few packages. First one is the Apollo server from Apollo server express and import express from Package Express. And we also need the http from HTTP packet. And you don't need to install it because we have it by default with NodeJS. Alright, now let's export and create a new class and name it app module. Inside this class we're going to have a constructor that will accept a resolvers. So here create a public variable and name it resolvers, and it's going to be of type resolvers. We have to import that from the generated folder and from the resolvers types file. And here we're getting an error because we have to import and use resolvers, not resolver. So add an S there. And here we're going to create a method that will initiate the Apollo server. So icing start Apollo. And this method should return. Of course it's a promise, and the promise should resolve an object with HTTP server, property of type HTTP server. And we have to return a server or property of type Apollo server. Now let's create a constant and name it server, and use the Apollo server class to create new Apollo server instance with some configurations. So here we need to pass our GraphQL schema and resolvers. And I'm going to start with resolvers and going to pass this variable here. And of course, we are inside a class, so we need to use the this keyword and then results. Now for the schema, we have the type deaths property. And we need to take this file, the schema dot GraphQL, and pass it here. And for that, we're going to use the read file sync method from our from alphas packets. So here Read File Sync and imported from fs. And before this, the server, we're going to create type deaths constant. And here we're going to use the Read File Sync to read the GraphQL schema from the schema that GraphQL file. So let me delete this. And here, let's continue. We need to specify the path. And because we have this schematic GraphQL file in the root directory, we can write it like this. Schema graph girl. And we will read this file with encoding set to UTF eight. Because without the encoding option, we're going to get back a buffer. But here we need a string. So remove the colon and just give the type deaths like this. Now we have to start the server, so await server that start. And then we need to create or use the apply middleware. And here we're going to add an express medulla. So let's first create an app with Express and use it here as a medieval. Ok, now, we need to return a HTTP server. But the app here is not of type HTTP. That server is this is of type express. So we're going to use the HTTP packets to create an HTTP server using the app application, I mean the Express application. So here, create a new constant and name it HTTP server, and then use http dot, create server and pass the up there. Then here, that's returned the HTTP server with the Apollo server. Now, we have to initiate a new instance and exported from the module file. So here, export constant up audio and then create new app module instance. Here we have to pass the results. So we have to import first the author is overs. So here import our resolvers, and I think we didn't export it from the author's ogres file. So let's do that here. Export, export. The author is solvers. And then let me copy this, go back to a module and import the author resolvers from go out or inside the Earth folder and inside the author results. Now, let's go back here and use the resolvers here, and then save this file. And in the next video, we're going to start working inside the main.js file. 12. Run and Test our Api: Inside the main.js file, we have to import the module from the module file and then create a bootstrap function. And it's going to be async. And inside here, we will extract the HTTP server and the server from the module that start a bottle method. And then we will use the HTTP server to initiate or start listening for connections are both for thousands. Then we will return a message to the console saying that server is ready at http localhost. And then the port 4,000. And here we need to get the path of the GraphQL gateway from the Apollo server. So I'm going to append here another string from the server, that GraphQL path property. And then we will get the a path for the GraphQL gateway. Alright, now, we still have to execute the bootstrap function are called the bootstrap function. And now let's save the main.js file and head over package.json file and add some scripts to run our app. So here, create a new start command and we have to compile our code and then run the main.js file. And this time we're going to use the dash, dash what option with no Ts, instead of using Node man packets. And in order to use this option, you have to have the latest version of notes. Yes. So I have the version 19 should have at least 18. So makes sure to update your Node.JS version. Then here, let's the path to the main.js file. So this folder, then source folder and then the main dot js file. And now let's take the TSO command here and put it in another command. So here, create a compile command and paste the TSC there. Then here we're going to run npm, run compile. So we will compile our code and then run the main.js file and watch for updates or watch for changes. Now let's save the package.json file and clubs. And here in the terminal, Let's run npm, run start. And we have an error. And that's because we need to add a query to our schema. So for now we're not using queries, but I'm going to add very simple query. So here, under mutation, going to run or create new type query inside it, I'm going to create a query that will return a string. And here the schema define a query. And then here also query and save. And this time we need to regenerate the types and create a resolver for that. So npm run, generate. And then inside the author resolvers. Let's create a query here and get method. So it should be a property and then cite it. We will have the get method and we will only return a string. So I'm going to send back a LK string and then save and run the application again. Here, npm, run, start. Alright, now we have our server at localhost 34,000 slash GraphQL. And here it seems that we added a slash, but we will fix that later on. Now let's go to our browser and navigate to localhost 4,000 GraphQL and click on Query your server so that we can get access to. Photo Studio. And from here we're going to test our mutations and queries. Alright, now we are inside Apollo sandbox and under root here you will find the query and the mutation. Now, we will start with dusting the mutation and tried to sign up. Of course, we have a dummy data, but we will only test the GraphQL gateway here. So to add the sign-up query, click on the plus icon and you will get the mutation and then the sign-up with the input. And this is how we define our mutation from the light, from the front end or from the client. So here, the input here is a variable and it's of type Sign-up input. So we're getting this type from the scheme, of course. And here we are defining the signup mutation or the sign-up method. Yeah, So this is just the type of the mutation, and this is the actual mutation. And we are adding or setting the input argument to be equal to the, this variable. And we can, ah, edit the input variable from here. As you can see here we are inside the variables section and here we can define all the required variables. Now inside the sign-up method, we will also define the return type and Saturday schematic GraphQL. You can see that the signup mutation will return a response and the other spouse have a user field where the JWT field. So here we can specify which property we're going to get. So in our case, we're going to get user and we only interesting and the id. And then we will get x, or we are waiting for the DWT. And that's it. This is the cool thing about GraphQL. Allows you to decide which data you want to get as a response. So rather than returning the whole user document with the email password, firstName and lastName, we can tell draft girl to only send back the ID and also the JWT token, of course, because we will use it to authenticate the user. Now let's run this query by clicking on Sign Up button here. And of course, we forgot to add the input. So this request will fail. Says that variable input is not, must not be null. So here, let's change that. And instead the arguments here, arguments section, we can find the input of type Sign-up input and you can add the necessary types here. So let me clear all of this in email, password and firstName, lastName. All of them are required. Now for the email going to choose just the user one at email.com, and for the password, going to send just password, firstName, user one, and last year last name, user. Now let's send again this query or this mutation and wait for the response. All right, we got the ID of one and the JWT token as this string here. And you can verify that this string is the same string we defined inside the return statement here. So the JWT or property. So we have our GraphQL gateway working with Express and Apollo server. And let's very quick also test the query. Yeah, so we're going to run the get method, makes sure to just leave it there and add the query get. So add this here in the getMethod. And for this query, we are not expecting to get any inputs. Therefore, we can just write the get method like this without parentheses, n without any arguments, then execute the query and we should get, okay, String. Alright, we have this here. And now we know that all our queries and mutations are working and that we can execute our resolvers. Now, we have to finish working on the signup mutation and also finished all the resolvers here. But before that, we need to use type around to create a user entity so that we can create a user and save it to the database. 13. install and configure typeorm: In this project, we're going to use type round to manage our database. There is a lot of organisms out there, but the most popular one is type ramp. And that's because it has a lot of features and it's easy to use, especially with TypeScript. Now an OR is an Object Relational Mapper. You can click on this link here and it will lead you to a Wikipedia page. And you can read more about object relational mapping here. Yeah. But TypeScript or our type ramp altogether stands for TypeScript, object relational, mapper, and type around. It's a library that makes it easy to link our TypeScript applications up to a relational database. And in our case, we're going to use Postgres as our relational database. And of course, diaper amps supports a lot of other databases, even MongoDB, but it's still in experimental stage. So if you want to use MongoDB, you can do that, but you have to add a lot of other setups. Because as you know, when we use Mongoose, we had some difficulties when we want to implement TypeScript with Mongoose modals. Yeah, So the same thing happens here with diaper m, but we have a lot of other options like Postgres, C-Corps, and my SQL or sequel light and all other databases. Now you can navigate to type parameter title and learn more about its features. But of course, in this project, I'm going to teach you how to install type Rahm, how to use it, how to create an entity, what type around, and a lot of other stuff. So let's open our VS Code. And inside the terminal, let's start by installing type around and the Postgres driver. And also we need another package named reflect Meta data because we're going or type or M is using the characters. And to use the characters with TypeScript, we need to install the reflect me the data here. So this is me that data. Otherwise we will get, we will not be able to run our application. So make sure to install that. And also if you didn't install the types for note, make sure to do that. Yeah, I have installed that from the first video. So I'm going to run this command and wait for the installation. Alright, now inside the main.js file, we have to import the reflect meta-data Beckett in order to use the characters. So let me copy this. And the reason why you choose main.js is because it's our main file for this project. So I'm going to import everything from the import. They reflect me that Theta brackets here. And we have to add some configurations here. And so the ts config that say some fun. So we need to add two more properties. First one is the emit, the characters, metadata and set to true. And also the experimental decorators also set to true. And these properties are very important when we want to run or use the characters inside our application. Now if you don't know what, what is the characters, we will learn about them when we start creating our entities. 14. Create user entity: Now that we have type ramp inside our project, Let's start by creating the user entity. So inside the folder, create another folder and name it user side here, create another folder named entity. And then inside the entity folder, create the user, that entity, the ts file. Now side here, we're going to import the character entity from type wrap. And then we will export a class name, a teaser. And here we're going to use the decorator entity. And this is how we define entities with diaper m. Now, the characters are just simple functions. Yeah, That's returns another function, but also uses a very specific arguments and they need the reflect me the data package to work. Yeah, So if you want to create a decorator, you can search online, but I will give you a very simple example. So imagine we have entity here. Imagine that we wanted to create an entity, the character. So I will do, I will create a constant and name it entity. And then I will create a function. And this function has to return another function. Now, the second function here should accept a target and accept a property key. For Tiki can be of type string and also a something called distributor. This grip there. And this one is of type property descriptor. Of course, we should not use the function distributor for a class. That's why we have an error here. Yeah, but you can learn more about the distributors inside the documentation. By TypeScript here, can read more about the characters. So copy this link and you can know a lot of things here about class distributors, e.g. here, how we build them here. So here we create a function with a constructor. The constructor is just a function. And then we use a lot of JavaScript methods here to handle or to extract the properties and the methods from the class and do something with them. Yeah, Now, make sure to, if you want to read more about them, make sure to come here and e.g. try to build your own tools or your own decorators. Yeah, but for now, let's remove this and continue with our user entity. Now, we need a first-name inside our user entity. So here, write first name. And this one is going to be of type string. And make sure it's a TypeScript string. I mean, with a lowercase as. And we need to use another character here. And this character is called a column. So column from type around and use it here. Column. Now we have the firstName, the lastName, last name of type string. And of course going to use the column again. And we need the email of type string as well. And then the column. And the cool thing about type where m is, even if you used a MongoDB or any other databases, you can define, you have to define the entities always in the same with the same structure. Except for Mongoose. Because as I said before, it's still in the experimental stage. Yeah. And it was there for a long time, but you still can work with it, but you have to create a schema. We cannot create an entity with Mongoose with diaper. Now let's continue with the user entity. We still need the password, and it's always type string here. And I'm going to add a configuration for the password. And to do that, we can pass a object here and say or a property, select and set it to false. And this mean that we don't want to we don't want the password to be returned to the client. Yeah, we we want to hide the password and this is how we do it with type. Now we can add a lot of configurations, e.g. for the e-mail here, we can. I mentioned that we don't want the image to be not. So we use the nullable property and set it to false. So the email will not be, No. This is like a validation with diaper n, but we're going to use another way for validation, more advanced way. Yeah. Now we still, still need the ID here. But because the idea is automatically generated by posteriors, we're going to use another decorator to define the id and that the character is called primary generated column. And here we will use that decorator. So primary is generated column. And here we will define the id. And as I said for PostgreSQL, we're going to get ideas numbers. Now let's save this and the next video, we're going to create the user service and start using the user entity. So see you there. 15. Create-user method | user.service: Now inside the user folder, let's create another file and name it user service tiers. And here let's export and create the class user service. And then going to add a constructor. And inside it we're going to define a public variable and name it user repository. And it's going to be of type repository. And we're going to import the repository interface from typewriters, so forth, repository from type ramp. And here at repository. And we have to pass the entity here. If you hover over this, you will find that it's required in order to use it inside our class. So here we will add the user entity and we have to import it from the file user entity. So for each user from the user entity or inside the entity file, then use or that entity. Now, we can start by creating the first method, which is the create method, where we will create a new user. So Async create. And then here for the, for the arguments, it's going to be a sign-up input. And we're going to use the automatically generated types here too. The type for the same input here. So let's assign the sign-up input argument to sign up input, interface and type. And we're going to import that from one level out and then two levels. And Site Generated going to select the resolvers type and the sign-up input. And if you hover over the sign-up input, you will find all our required properties here, like the email first name and last name and the password. Of course, without the ID because he's, It's automatically generate. And here fix the async. Now, first thing we have to do inside the create method is hashing the password. For that we need the another package. So let's open the terminal. And I'll stall the Beckett named decrypt. And we would use it to pass our password and also compare the passwords when we want to sign in the user. So here, npm install the crypt. And we also need to install the types for, be correct. Then run this command. Wait for the installation, and that's it. Let me clear this and close the terminal. And here, let me abort the Big Rip class from the crypt. And here we're going to create new passwords, a hashed password. Wait for the encrypt. That hash. And side here, we're going to pass the sign-up input. So sign up here. Input that password. And then we need to choose a salt rounds. So here, going to choose ten as the Salt rounds. And here we're getting an error because the password, if you hover over this, you'll find that all the properties inside the sign-up input type is not required. To change that. We have to go to the schema that GraphQL. And aside here add an exclamation mark on all the properties here. And let's do the same thing for the user. So we need to only for the password. Yeah. Because we were not going to send it back. And then it sets, Let's save this. And we need to open the terminal and generate the types. So here, npm run, generate. And that's it. Let me clear this or just close the terminal. Go back to the user service and the error has disappeared. And now the password is of type string before it was of type maybe or something like that. They will use another interface or a class here to define not required properties. But when it is required, we're using this type here, but it's automatic, degenerated. We don't care about that. Let's now continue building the user. Now, create a user constant, then use this dot user repository and then create method from the user repository. And here we're going to spread the user or the sign-up input, sign up input. And then we're going to add the password here. So I know that inside the sign-up input we have already a password, but when we spread the older properties like this inside an object and then adding another property with the same name that exists in the sign-up input. We're going actually to update that property. And we're going to have the password set to this value to the HashSet password here. Now, let me, we need to save the user. And to do that, we need to use this user repository dot save method and pass the newly created user document. Of course, we're going to return this document to the client. So it's returned this and wait for it. And then save. Now in order to use the user service inside the Earth resolvers. And because the author is solvers, is an object, we cannot add a public variable and set it to the user user service type. So we have to create an instance from the user service and export it so we can use it inside the author results. Yeah, so, right, export, then constant User Service and going to add a new instance of user service. And here we need to pass the user repository. And for that, we need to create the data source. And from the data source, we're going to get the user repository. We will do that in the next video. 16. add app data source: Now let's create the app data source and then come back here. So inside the source folder, create a new file and name it, does data source, the Ts. And here we have to import the data source class from diaper. And here we have to export a constant, name it up data source. And it's going to be equal to a new instance of data source class. And here we are going to have the type of the database. And in our case, we're going to use the Postgres database. You can see here that we have a lot of databases, as I said before, have my sick or have a lot of other databases like MongoDB here. So for us we're going to use Postgres. And you have to choose Postgres in this project because then after this we're going to use Docker to run Postgres database inside our local system. Yeah. So if you want to follow this course, you need to also choose Postgres. Now, we need the host for the database and our case, we are going to run the database at the local host. And we're going to choose the port. And for Postgres, we have the port 5432, and we need a username for the database. All of these information would be also added, are used when we initiate our Postgres database with Docker. So here the username going to choose Admin. And for the password, I'm going to choose also admin. And then the database name, it's going to be main database. And now we have to define our entities. The entities. It's an array that contains all the entities files. So you can specify the path of its entity. But there is a better way to do it is by first, we have deselected dist folder and then add two stars for to choose or to search inside any folder. And then add one star here, then dot entity that G has. Now, by using this path, we're going to select all the files inside the dist folder and inside any folder that exists inside this folder that has a dot entity at the end of its name. Yeah. Now, still need more properties like the logging. We don't want to get a sequel queries inside our terminal. So for logging, I'm going to choose false. And we need to add the synchronize option here. But make sure to set it true only for when we develop our database or our project. And you can read here the documentation of this property. And that is a warning that if you use the option and the production mode, you will lose like you will use production data. So basically this option here, we'll update the database. And because we're using Postgres, it's a relational database. It will, the subsequent will update the database tables between all the entities. But this is not a safe way to update the schema. Therefore, we will only use it. Use this option here. Then we will work with, we will add make patients, and we will get rid of this option here. So for now, let's keep it set to true and go back to the user service. And we have to import the data source, data source from the one level out, two levels than the update. So it's there and we will use it here. Data source, then dot Git repository. And we have to add the target. And the target is an entity type. So we have to pass the user entity here so we can get the user repository. Now in the next video, we're going to start working with the author is solvers. And we're going to finish this sign up or not finished, but start working on this sign-up method. So see you there. 17. Create signup resolver: Now inside the signup mutation, Let's remove this code here. And first thing we have to do is creating a new user. So constant user than wait for the user service. And he can afford that from users slash user service. And then we're going to use the create method and pass the input or the sign-up input. And for us, it's just the input argument here. Now, the return type of the signup mutation is object that has a user field with the JWT field. So we need to create a JWT token. And for that, let's open our terminal and install npm JSON Web Token. And of course we need the types, types JSON Web Token. And let me clear this, close the terminal. And here we have to generate a JWT token using the JWT package. Import JWT from JSON web token. You know how to do this, we have to use JWT than the sign-in method. Here. We will pass the payload. And this time I'm going to add a payload with email from the input that e-mail and a user ID from the user ID. And we need a JWT token. So we have to create and dot length file and add the JWT token variable there. So in the router level of our project, let's create a file. And inside here a JWT key, and add some random characters. And then save. Then we need the package that will read the files for us inside a TypeScript project. And that's the brackets. So npm install dot. Then that's, that's safe. Not save dev. Let me clear this now. Close the terminal and we're going to use the dot m that gets inside the main.js file. So here I import everything as in. From here we're going to use in the Gothic and call this method. And make sure to import this in the top here for all the import statements, and then Save. And here inside the bootstrap method, we're going to check if we have a process that in the JWT token or not. Yeah. So if you don't have GDB T key here, if you don't have this, we're going to return or throw a new error. And it's going to have a message that say database. Alright, now let's save this, go back here, close the main.js file, and going to the process that in that JWT key. So we have to add an exclamation mark here because we already checked inside the main.js file. If we didn't, we didn't get the DWT key. When we run the app, we're going to throw an error and we will not start the API. Now we need to add a new object here. And we will add the expires in property. And here we can define the time in which we want this JWT token to be expired. So in my case, I want to expire this token in seven days. So you can choose anytime you want. Let's save this. And of course we can add days like this goes. If you hover over exposed in property here, you'll find that it except like time with seconds or with just some strings like this, two days or 10 h, seven days. There is a lot of Ways to define the time here. So now after creating the JWT token, we have to return an object with the user and the JWT, and it's going to be set to the JWT token. Now, the error has disappeared because we are returning the correct value here. And we still need to check if we have a user with the same e-mail that already exists inside the database. So for that, we have to create a new method inside User Service. And It's going to be named find one by email. And we're going to get the email as a string. And then we're going to return 08 and use the user repository to find one by fast the e-mail here. Now save this and go back to the resolvers. And here, create a new constant and name it, exist or existing user. And here we're going to use the User Service that find one by email and the email from inputs that e-mail. And we need to wait for this. And then save. And we need to check if we have an existing user, then we need to throw back an error. And for the error, we need to use a very specific type of errors that comes from or with GraphQL. And this is a GraphQL. And we can import it from a graph deal. Yeah, so if you didn't install graph here, make sure to install it and also installed the types for GraphQL. And here we need to add a message. So the message is going to be user already exists. And we can just send back a message or we can add some other configurations, like the extension or the extensions. And here we can add the code of this error. So another object here, Code property. And I'm going to send back a bad request code. So if you want to send back some information about this error, like maybe the fields or the error type like this. You can add all of that inside the extensions object here, and it will be sent to the client. Of course, if you want to create a custom errors with create the like we did inside the other two projects. Create a separate classes for its error. And of course, you still have to use the GraphQL here to create those classes. But it's really not required because we already have a class and we can use it every time when we want to throw an error. And it will be parsed as the graph care or yeah, we don't need to create any new classes from that. Now, that's it for the sign-up method. The next video, we're going to create the sign-in. 18. Creating signin resolver: Now we cannot work on the sign a mutation here. So the resolvers, because we still didn't define the sign in mutations are the schema. So first let's do that and then go back to the Earth resolvers. Right here. Let's set the mutation, Let's create the site in mutation. And we'll get an input of type, sign-in input. And by the way we can, we can use another structure here. So rather than adding a argument and the time for that argument, we can define all the arguments here, like and email of type string. And it's required. And then add a comma and we need a password as a string. Yeah, but because we are using the types also inside our resolvers, inside our user service, we need to define its input type as an object here. So let's change this to input sign-in input, and this one is going to be required. Again, we're going to return an earth response. And of course it's required. Now, we need to add the sign in here, input that's created here. Input and sign in input. We only need the email as a string, and it's acquired with the password as a required string. Right? Now, Let's save this and open the terminal. And we have to generate the schema. So npm run, generate originary the type of the schema. Alright, now close the terminal and close the schema dot GraphQL file and go back here inside the author is solvers. Under the sign-in. Let's define the or under the sign-up, let's define the sign in method. We should get a succession for this method here. Just wait for a second here. Sign in. And if you hover over it, you'll find that sine n is of type resolver. So we did generate the types correctly. So here, that's defined current input and the contexts. And as I said before, we're going to talk about the contexts and just the future videos. Yeah, so here we have to check if we have a user with that email saved inside the database. So I'm going to copy these two lines here from the sign-up method and paste them here. And change this with just user. Here. If we don't, if we didn't have a user, we're going to send back a long written so error. So here, wrong, Cree potentials, outer and the code still bad request. And then we have to check if we have, if the passwords inside the input is equal to the hazard password from the user database. So let's add a constant and name it correct PWD, and then await for B crypt. And we have to import that. So this dog Alport be corrupt class from the decrypt packets. And here going to use the method compare. And this method accepts the buffer or the the input and then compare it with the acid password. Yeah. So here input password. And then we will get the hazard password from the user password. But in our case, we cannot get the password from the user. That's because inside the user entity, we said the buzzword canon, select false. And that's why we will get here and define or not. Yeah. But we can change that site, the user service, and instead they find one by e-mail that's removed it, find one by method. Here. Let's create a query builder. So from the user repository, create a query builder. And here we're going to declare a variable and name it user. And equal to query builder. Here. Add a Ideas for user, and then we will use a method to select the user password. So here, user password, now the query. But there is a method that helps with building SQL queries by just adding some other methods like this. Yeah, so we're going to create, degenerate a sequel query here using the Query Builder to select the user password. And then we're going to find or select a user where the email equals to e-mail. In here we will define the variable email. So what's happening here is that we're going to check if the email equals to this variable, yeah. And to define variables inside this query here, we add the colon and then the name of the variable. And then in the second argument here, we have a object containing the values of that variable here, and it should be in the same name as we wrote here. That's why when we execute the query builder here, this will be changed to email equals and then the email of the user. Now, we need another method here to get one user. And if you hover over user now, you'll find that user as a promise that will return either a user or not. Therefore, we need to await here, and this time we will get either user or not. And that case, we're going to return the user and save the user service. Go back here. Or actually let's go back to the user service. And here, I forgot to mention that we should add a select here. Yeah, this is going to be the primary select and we're going to select the user document or all the columns instead the user document. And then we will add a select where we will use the password. And then we will do the filter here and then send back the user with the password. Now, unfortunately, the select force here only hides the password from the find methods. So either find one or find by something. Yeah, but it doesn't hide the password. When we save the user here or saving new entity. Therefore, we need to create a constant here inside the create method. Create a constant that holds the service user, and then create another Find method after this here. And search for the user with the ID. Yeah, but this is going to be a waste of time, especially when working with GraphQL. Because with GraphQL, we can hide passwords or anything by just removing the fields here. So for password, we can remove the password field. And then inside the off response, inside the user, we will not get the password. This is how we hide credentials using GraphQL. But here I just wanted to show you how you can get a height field from the database using the Create Query Builder if you're not using GraphQL. So I will leave this code like this just for you to remember how to get a high tunnel, like the password and sad user entity, I'm going to remove the select false here because I don't want to change or to write the same code every time I want to get the entity. And I will add a common tier two. To indicate that this, you can use this approach only when you have a hiding. So here, only if entity that Carlin and you have the select set to false. Now save the user service and close these two files and go back here. And that's a very quick continue with the sign-in method. So now we need to check if we didn't have or we didn't get the correct password, then we will return an error. And here I'm missing the air, correct or see and hear, throw new graph girl error. And it's going to be the same message you credential, wrong credential. And the same extension. So let me copy this. And here I'm going to copy the extension. And then we have to regenerate the JWT token and then return the user with the JWT. So I'm going to copy this and paste it here. Now the user is going to be returned with the password. But because we changed that inside the schema, we will not return or the graph gear will not select the password from the return statement of the mutations here. Now, of course, you need to open your terminal and run npm run degenerate because we updated the schema. So let's do that. Npm run generate. And that's it. We finished working on the sign-in method. 19. working with the graphql context: Now we're going to create a query that will return the user email and the user ID. And again, we're going to start from the schema. Does GraphQL and crea create a new query and name it current user. And here we're going to send back a JWT payload. Now we have to define this type. So copy the JWT name and here create type, then JWT, fade out and cite it. We will have the email of type string, and we will have the user id of type int. And both of them are required. Now let's save this, close the schema that GraphQL and we have to generate the types. Run npm, run, generate, and close the terminal. Go back to the author resolvers. And here inside the query, let's remove the get method from here. And the current user method. Hearing it. Parent, we need the input and the contexts. All right, now we have an error here because we didn't add an input variable to the current user query, like we didn't assign the mutation, so we will not get an input argument here. So let's remove this and replace it with our x like this. And just to make it clear that we don't have any arguments, I'm going to replace it with an empty object. Alright, now here we're going to extract the JWT payload from the JWT token. But we used to add that logic inside a middleware and then use that middleware inside other routers. And then get an object from the requests containing the user payload. But that's of course inside a RESTful API. But because we are using Express with GraphQL, we can do the same thing. We can add. We can use a Create Image and then use up the 2s method to apply the Midwest here. And then we will get the, we can extract the JWT payload from JWT token. But we can implement the same process with Apollo server by adding a contexts that will contain the request and the JWT payloads. So here, say the Apollo server at a context. And it's going to be an function that will return an object. Now, before start working on this function, we have to add a new interface and name it contexts. So here, export interface, then my context. We have to extend the Express contents so we can get access to the request. And here we will add our custom properties. But first, we have to import the Express contexts from the Apollo server. So here, Airport Express context from a photo Server Express. Now here, that's our first custom property, which is the current user. And it's going to be of type T, W T payload. And the DWT payload is imported from the incinerated types. So make sure to import that from this path here. Then we have to add another property, which is the authorized property. And with this property, we can check if we have an authorized user or not. So this property is going to be of type Boolean. And save this. Go back here. And we need to add the mike contexts interface with the Apollo server. So going to return Apollo server with my contexts of type, my contexts. Alright, Now, go back inside this method here. And now we can extract. From the dysfunction, extract the request and the response because we extended the Express contexts. And here, let's create a constant and name it payload, and then use the DWT packets from DWT, we have to import that. So let's do it. Important, JWT from Jason token back here, CWT dot verify to verify the token. And we're going to get the token this time, not from the session, but from the headers. So we will use the request payload or the tethers. Make sure to select headers, no tether. And then we're going to get the token from the authorization header. Yeah. So the Heather's can be no. So let's add a question mark there. And now we need to pass the JWT secret key. So I can get that from process that the DWT key and add an exclamation mark. So we can tell TypeScript that this is not null. And now we need to return that payload here. So have an order here, because it seems that the request is also can be new or undefined. So let's add question mark there. Or let's just check if we didn't have didn't get a request. Yeah, we will return an object and we will come back here in just a second. Now let's define the current user property and give it the payload. And then we will also send back or pass the request to the resolvers. And then we will the authorized property, and the authorized property is a Boolean. So we will check if you have a payload or not. So if you didn't have a paid out means that the user is not authorized. So for that I'm going to use a special syntax. So our two exclamation marks and then Abby paid out. So if the payload is null or undefined, the first exclamation mark is going to return true. Then the second exclamation mark is going to return the opposite of true, which is false. And then they authorized, it's going to be set to false means that the user is not authorized because we have a null, a pilot. Now, if we didn't have a request, which is a problem for us because we cannot extract the JWT token. So we're going to send a on the same object but with Korean chooser set to null and the request, of course, and the authorized to false. We have to return this. Alright, now, let's remove the question marks from here. And actually here we have to check if we didn't get or we didn't have a request for authorization header here, then we'll just send back this object. Otherwise, we will extract the payload and sent the required property. Now let me adjust this code a little bit to do this and save this file. Then close it and go back to the Koreans user resolver or query here. And we're going to check if the authorized property inside the context. True or false. Yeah. So if the authorized property so here authorized. And we are not getting the authorized from the context. That's because we have to update the code chain here. Yeah, and update the types of the results. So we need to specify the context type and say so under the config here. And in the same indentation level, contexts, type, or contexts, types by type, and specify the path or the file that contain our context. In our case, are my contexts exist inside the module file. So make sure first to export the mike contexts interface and come here and add the birth according to these generated folder. So according to the generated folder, the module or according to the resolver type that is exist side the generated folder. The module file is one level out, then module. And we have to select the interface. So we're going to add a hashtag here and add the name of the contexts. So my contexts. And in this case, we are selecting a, a, an exported interface or variable from the file using a YAML syntax. Now let's close the co-gen config file and open the terminal. Then here we have to run the generator commands. So npm run generate, and then we will get our context of type, my context. Yeah. So let's wait. Right now. If you hover over contexts, you should have the bike contexts type here. Now let me close the terminal and authorized is of type Boolean. So we're going to check if the user is not authorized, then we're going to send back a unauthorized error. So Throat knew GraphQL and MS is not authorized. And we need to add an extension. Extension. Then add the code. And here we will add the code. Unauthorized. Alright? Now if we have a authorize that user or going to return from the context, the current user. Now let's save. The current user is of type G deputy payload contain the email and the user ID. The type name is just something related to GraphQL. But inside the GraphQL schema or a response, we're going only to get the email and the user ID. Alright, now let's save this. And in order to test all of these resolvers here, we have to have a working database. So in the next few videos, we're going to learn how to use Joker, of course, how to install Docker and then use Docker to install the Postgres database and run it in our local system. 20. what is Docker: Docker carves up a running Linux system into small containers, which is its own little world with its own programs and its own everything, all isolated from anything else. These containers are designed to be portable so they can be shifted from one place to another. And Docker does the work of getting these containers to and from your systems. Now, what is the container? You know, when you build something with e.g. an OTS and then you push your code into GitHub and somebody else tries to pull and run your code inside his local system, but it didn't work for him. And then he will think that your code is garbage. And you may also think that you are not a good developer. But sometimes that's not the case because your Node.JS applications requires a very specific softwares and unique environment to work. And these requirements are only exists inside your local system, where you are, where you developed your Node.JS application. Like if you have Linux and instead of Windows or you have an older version of nodes, yes, all of these variables cannot be the same in all systems. Therefore, Docker has introduced something called container. A container is a standardized unit of software that allows developers to easily there from its environment. So you can develop e.g. your Node.JS application and build a container around it and push it to Docker Hub as an image. And then anyone can pull that image and run it in his own local system. In that case, your NodeJS app will be running on the same environment as in your local system. 21. Install docker Linux: Now to start Docker on your window or on Linux system in general, you have to go through a few steps. So head over darker tags. And you can use this path here or this URL. And or maybe you can search on Google for installing Docker engine on your pinto because URL's can be changed in the future. Now, the first thing you have to do here is make sure you don't have any older version of Docker. By running this command here, you can delete all outdated versions. Now, the next step is you have to update your APT packages. And then I'll start with some few beggars and see if that will be used in the next steps. Yeah, then you have to run these commands to tell your system that it's okay to use. Software is from the Docker Engine. And then you have to run this command to set up your repository. And the reason why we have to add up our repository or setup a repository that is connected to the Docker Engine is because we're going to pull images from Docker Hub. And sometimes we have to push images made by us to the Docker Hub. So we need airports was like that. It's similar to repositories with GitHub. Yeah. Now the next step is to install the Docker Engine. After setting out their repository. Of course, you have to update your packages again. And if you've got any errors, run these commands. And then finally, you can install Docker by running this command. After that, if you want to verify if you have successfully installed Docker, you can run an image that existed by default with Docker called kilowatt. So run this command, sudo docker run hello-world, and you should get a string back with HelloWorld. 22. Images to containers: Now that we've got Docker installed and talked a little bit about what Docker is, let's try to use it. So with Docker, everything begins with an image. An image is every file that makes up just enough of the operating system to do what you need to do. Now, the command to look into your Docker images is simply Docker images. You can see here that I have a lot of images and things going on here because I used occur all the time. And for you, you may have some images like you've been to or HelloWorld. Now it's image has a name and a version, bike latest or something like this. And also its image has an ID. And here we can find when this image has been created. And here you can see the size of that image. Now, let's take an image and then run it inside the container using Docker. Let me clear this terminal and then run right docker. Run command. Now, this command takes an image and turns it into a living running container with a process in it that's doing something. Now, after docker run, I'm going to specify the image that they want to use. And for me, I'm going to use who've been to. And for you, if you didn't find you've been to installed by default in your joker. Don't worry because by running this command, Docker will try to pull the human to image with the latest version from the Docker Hub. So of course you have to have an Internet connection to do that. Now, still didn't finish from this command here. So docker run, you've been to. And then we said that we're going to run a process in this image. So let's run the bash shell because I want to run some commands inside you've been to with the terminal. And also for that, we need a flag to interact with the terminal. And the flag is the D flag. So D stands for terminal and I stands for interactive, terminal and directive. Then you've been to bash. And now let's run this schematic for you. If you don't have you been to, you will see a downloading process. Alright, we're inside the Ubunto image. Now, if I take a look here, I'll find that we're inside the we have the, you've been to environment. And just to make sure going to run this command to take a look to this file LSB dash release. And we should get the version of you're going to have here, the version 20 and the distribution ID. You're going to now to your exit this image. You can write exit like this or Control D does for exit. Now, in order to see the last exited image, we can open a new terminal here and docker ps and then dash latest. So if you run just ps, you will find, you will get all the running images. And with L, you can get the latest exited image. If you run this command, you'll find that the image is, you've been to. And you'll find the command here that was running site this image. And of course, where does create it? And it exited in about 4 min ago. Yeah. And this isn't the name of that container, not the image. So this container is running the urban to image and running the basket land. Yeah. And it was created 6 min ago and exited 4 min ago. And this is the idea of the container. And they said the name of the container. And by the way, this name is randomly generated by Docker. Now let's go back here and run the, you've been to image again with the bash shell. And inside that you've been to image. Let's create a new file with the touch command and name it my file. And take a look here and we will find my file. Then let's exit this. Or I let skip this container running and go back here and then run the same command, docker, run TI for terminal interactive. And then you've been to and run the bash shell. So we're running the same image with the same flag in the same process. And here, if we take a look, We will not find the file that was created here. So its container runs an image and it doesn't get affected by other containers that are running the same image. So when we create a file here, doesn't mean that we're going to get the same file inside this container that runs the same image. So its container is insulated from the other. Even though they both running the same image, you can think of them like two computers running the same version of you've been to. 23. containers to images: Now we can see we went from an image to a running container. And when we start a container, the container is still there. It didn't get deleted. So I can look at the most recently exited container with a docker ps command. But of course, we need the dash l flag to get the last stopped container. So here you can see that I have a container that was running just a moment ago. And you can see all the informations about this container here. Now, let's say I have a stopped container. I started from a base image. Ion started my own software. I've got a container that has my software installed on it. Now, I want to use the same container that has my own softwares in it in the future, or maybe share it with the community. So to do that, we have to use the docker commit command that takes containers and makes images out of them. So to use the docker commit, let's first create a new container. Let's clear this. And one. You've been to, of course with the TI flag and then you've been to and run the batch command. Now inside this container, we're going to create a file, and we need to use that file in the future with this container. So we're going to create an image from this container here that's using the touch command and create file and name it like secrets. We have our file here. Let's exit this container with Control D or just write exit. And then let's take the idea of this container by running docker ps dash L. Then we have here the idea of this container. So let's copy this id. And then let's use the docker commit command and paste the darker or the container ID here, then run the docker commit command. Now, we would get an image out of this container. And this is the idea of that image. But using a long ID like this, it's not a good thing because you can lose this id or maybe you can find it difficult to run commands using this long string. So what I'm going to do next is going to a tag this image with a human-readable name. And to do that, we don't use the tag flag. Then we add the ID of this image from the colon to the end of this string and paste it here. And then choose a name for this image. So image what e.g. and run the Docker command. And now if we want to check if you have an image with the image dash or underscore one name, you can run Docker images and then search for the image name here. You can find it here. So we have image underscore one, and here we have the ID. And it was created for minutes ago. So this is how we can create images from containers. Now, there is another way to commit images rather than using the commit command. And it's acumen. And that's by, first of all, let's create a Docker container and take the idea of that container. Then we're going to use the docker commit in another way. So here let's to create a file like my file. And let's exit again. And then we're going to check or to get the idea of this docker container. And now we can take the name of the container. Here, a human-readable name, and copy it and then run docker, commit, then the name of the container, and then the name of the new image that you want to create. And this time I'm going to choose image two. Now we're running this command. We would get the same output from before. But if you run Docker images now, you can find an image to presented in our local Docker repository. 24. running postgres database with docker: Now we're going to learn more about docker, and in the same time we're going to run our Postgres database. And for that, we need to pull the postgres SQL image from Docker. To do that, we have to run docker, pull. Then the name of the image which is Postgres. You can add a colon and then the latest tag. But by default, well, install the latest version. Now I'm not going to run this command because I already have this image in my local system. So now I'm going to use the docker run command to run the postgres image. Of course, with the DI flag here and the postgres image. Now, we're not going to run this command. Take this because we have to add some configurations. And this time I want to add a custom name for my container. And for that we have to use the desktop named flag and then choose a name like up. Underscore. Both stress. Now, in order to establish a connection to the Postgres database, we have to expose a port and Postgres natively uses the 5432 port to accept connections. So we have to expose this port from the container using the dash P flag. And now we have to map this Postgres port with a port from the container. And I'm going to choose a 545 5 v and add a colon here. Now, you probably didn't understand what I'm talking about here. That's why I prepared a diagram here to simplify the idea of exposing posts. So here we have the Postgres, postgres app container or outputs glass container. So let me change the name here at Postgres. And this container has an image running inside it. So this image is the postgres image. And Postgres natively uses the 5432 port. But we cannot connect an app to the this to the Postgres image from the 5432 port. When we run this image from the container. Because as you know, containers are isolated from each other and from the local system. So this approach will not work. Therefore we have to use another way, which is exposing another board from the container and map this port to the Postgres port or to the image that is running inside this container. And then in order to connect to Postgres database, we have to connect to local host colon 5455. So we have to connect to the container, not to the image itself. Now, if you have more than one of, you can of course connect them to the same container that's running the postgres image. Because here we're using localhost. But of course it's not recommended to use the same database with other applications because you can lose data and destroy your database tables, like e.g. if App one is registering a user into the database with an email a, then in the same time we have the app too, registering also a user with the same e-mail. That case, you will have instead of your database to users with the same email, even though you have validations running in your applications, doesn't prevent such mistake to B happened. So what you have to do is creating another container with the same image. But this time you have to name that container with another name and then also use another port here. But of course you will keep the same port for the postgres image. So here changed the name to, up to and here the Postgres icon. So we have the Postgres image here and you have to change this port. Otherwise, you cannot connect to the container, or even you cannot build this container because you're using the same port in another container here. So I'll just change it to 5456. And then let me remove this. The outdo is going to connect to this address, to this container. And this is how you can have, like if you're building a microservices out, this is the right approach to connect to database. So it's app has to have its own containers that runs the database. Now, I don't know why I'm scrolling up and down over and over like this, but let's just ignore that and go back here inside our terminal and finished the app postgres container. So we have our posts here. Now. We have to define some environment variables. And it's required to run Postgres or to connect to Postgres. Now, these environment variables are define also here. So we have to define the same information like the username, password, the port, and we changed the port 25455. Now let's change this here. And the spring, the terminal here, and try to copy the same information. Now, to add a, an environment variable, we have to use the dice e flag and then name the first variable. And first variable is the Post truss. And it should be all uppercase. Now, Postgres underscore user. It should be the same as the username here. So it's going to be equal to admin. And to define another environment variable, we have to use again the dash g flag, and then write Postgres password. Again, all uppercase. And then the password is the same password inside the app data source. So password is admin, and the last environment variable is the database name. So again, dicey, then Postgres. So most crass. Then underscore db for database. And the DB database name is main. Lowercase. It should be the same name as presented here. Of course, the host name is local host because this container is going to run inside our local system. Now, let's run this container and wait for the result. Here we go. We have some login going on here. And these, these information is related to Postgres. So we are initiating a new connection to the database. And here we go, we have database system is ready to accept connections. 25. Test Graphql endpoint: Now, in order for our app to connect to the Postgres database, we need to initiate the app data source inside module.js fall. So side here, Let's first import the app data source. Data source. From a data source. And inside these starts Apollo, and from the beginning, we have to wait for data source initialize. Now the initialize method is going to connect to the Postgres database and take all our entities and save them as database tables. And now before testing the API, we need to fix something and study context here. So if we have an valid JWT token, they verify method is going to fail. And when it fails, we will not be able to connect to the GraphQL endpoint. And we will not be able to use resolvers that doesn't require authentication because the method is going to throw an error and it will break our whole application. So what I'm going to do is I'm going to put the verified method inside a try catch block. And in that way, we can prevent errors coming from the verify method to be thrown to the outside of the context method here. So the first thing I'm going to do is going to create a lead variable here. Then remove the constant from here, and then copy all of this or cat or this, and create the try catch, catch block. So here, try catch the error. Then side here, basically payload with the verify method. And if we failed here, we're going to catch the error inside the catch block. But we're not going to throw the error here because in that case, we're going to do this same thing that they verify method was doing. So here I'm going to set the payload to be no. Now, if we didn't get the authorization token, they verify method is going to fail and the payload is going to be set to No, Yeah. And the authorized property is going to set to false. So we don't need the if statement here. And when we don't have the authorization token, we're going to pass an empty string and the verify method is going to fail anyway. Now, the reason why we're doing this and we were using the if statement here, is because they verify method only accepts strings as a token, doesn't accept undefined or null types here. So if you didn't have theorization, we're going to pass a string. Now in this way, we can reach our resolvers even though we didn't get a token. Now let's save this and open the terminal. And finally, let's test our GraphQL endpoint. So here let me expand this and run npm, run, start. And before running this command, we have to change something instead of beggars adjacent file. So we use the node dash, dash swatch here, but this command doesn't watch for the changes inside the TypeScript files. And we need to add the flag watch like this. But in this case, we have to add only one and psi. Because if we use two and signs here, we will wait for this command to be executed and finish running, and then we will run the node command. But the watch mode here doesn't finish, doesn't, it doesn't have an n. Yeah, that's why we name it watch mode, Yeah. And in that case, we will not execute this command. So we have to remove this and use only one and sine. That case, we will run these two commands in the same time. But this is very dangerous because imagine if we didn't have the dist folder here, and we ran the node, node command. And in that case, denote command will break, but the compile command that will be executed. And it will watch for changes in sign the ts files. But when the DOS command generate the dist folder. We will find that the node command doesn't work and it doesn't watch for the changes, so it will not know that. Now we have this folder and in that case, our application is going to stuck on the compile stage. Yeah. So the point I'm making here is that we cannot use the dash, dash watch command here. And we have to use node man again inside this project. So make sure to install Node man again in the dev dependencies. Then use it here with the node command without the word smoked. So let's delete that, then take this command and put it here. Then let's delete this and use node one. And with the e flag and then ts, then they stash exact. Then we're going to execute the command, the compile command. Here, npm, buy-in, compile, save this. And let's try to start our app. Right. Now. We didn't get any errors related to a database, means that we successfully initiated a connection to the Postgres database. Now, let's go ahead and dust are GraphQL endpoint side the Apollo sandbox, we have here a green icon means that we successfully connected to our GraphQL endpoint. Now, let's try to sign up a user with the same credentials here and check if we can save users to the database. So let's run these sign-up query here. And if you don't, if you didn't have this from the previous videos, you can just go back to the root here and click on mutation, then choose the sign up. Actually, I'm going to generate the query again just in case. So let's add the sign-up query or a mutation. And the two fields, the user. And here we will just wait for the ID to make sure that we successfully saved the user inside the database. Now, we will use the same inputs here. And from the sign-up mutation. Alright, we have here the JWT token, and most importantly, we have the ID set to one. So if we signed up a new user, we have to get that. We have to get an idea of two. So let's change the e-mail here to user two and the firstName user2, and then run the sign up again. And let's wait for the response. You have to get ID two. And he would go. Now, we are sure that we're saving users and into the database and we're getting also results from the database. Now let's test the Korean chooser resolvable because the sine n mutation is, has the same logic as the Sign-up. Yeah, So let's test the Korean user. And for that we need to send a Authorization header. So let's copy the JWT token. And here let's click on the Settings icon and add the authorization headers. So here at theorization, you can just start writing authorization and you'd get some suggestion here. Choose authorization and paste the token. Yeah, it makes sure you have the cookie is set to off. Otherwise, we cannot connect to our GraphQL endpoint. Now let's save this. And let's run the gradient user query. So go back to the root here. Let's delete all this and click on query, then add the current user query. And let's wait for the email and the user ID so we don't need the input. So let's just run the current user query. And we should get the email and the ID. Here we go. We got the user to, because we use the JWT token when we signed up as user2. Now we can get the email and the user ID. It means that our context is working and we can extract our payload from the token. Now, in the next video, we're going to create an image out of this container. 26. from postgres container to image: Now let's create an image that will run this container for us. So let's exit from this container. And then let's clear the terminal. And let's use the docker commit command to create a new image from the app postgres container and name this image message database and run this command. And now let's try to run this image where Docker run than TI for terminal direction. And then I mentioned the image name. And before running this command, we have to expose also a port here, because when running an image using Docker run, we're going to create a container and the message, our database image is going to run inside that container. So we're going to expose the same ports that we exposed inside the app postgres container using the desk P flag at the port 5455 and then a colon, then the port of the Postgres database 5432. Now, you probably didn't understand why we're using the same ports here. And that's because you're thinking that when we run the NSG add DB image, we're going to actually run the app postgres container. Yeah, but that's not the case because when we run this image, we're not going to run the app postgres container, but we're going to run the postgres image with all the environment variables and all the configurations. So the app postgres container has nothing to do with the MSG AB DB image. And now when we run this command, we're going to get a container that will run the postgres image also with all the environment variables and the configurations. So I hope now you can understand why we have to expose the same ports again. Now whenever we run this command, we're going to get a randomly generated container. Because when we exit from a container, the container doesn't get deleted. But we don't want that. We want the every time when we finished using a container, that container has to be donated. And we can do that automatically by adding a new flag to the rand command, which is the RM command. And now we can run this command. And when we finish working with the container, it means when we exit from the container, the container gets deleted and we will not get a bunch of randomly generated containers inside our Docker repository. So now let's run this command and wait for the database connection to be established. Alright, we have our database running. Let's go back to our project and the terminal. Let's run npm. Run, start. Make sure you still have the 5455 bullets here. Let's run the command. We can see that we didn't get any database errors. Now I have here a double slash for the GraphQL endpoint, and that's because it didn't change that here and say the main.js file. So I'm going to do that now and save the main.js file. Wait for the reload, and then you have to get the correct year. Now, navigate to this URL. And inside the Apollo sandbox, that's the API. So you can see here I was testing the validation for the sign-up repository. So if we signed up with the same email, we're going to get a bad request error message saying that the user already exists. So we know that that part of the sign-up resolver is working. Now, let's sign up as usual one. And here, firstName user1 and run sign up. And we should get a user with an ID set to one. Right? We have the ID and we have the JWT token. 27. Defining the room Schema: Now it's time to start working on the room service. And as before, we're going to start on the schema that graph DO file. But I'm not going to write the GraphQL schema of the room service inside the schematic graph Gail fail because it's, you know, it's always a good practice to split files into small pieces, especially if you have a big file. So that's what we're going to do here. Let's start by creating a new folder inside the source folder and name it. Booms. And then here we're going to have the rooms or room that GraphQL. And then here we're going to write our GraphQL schema that is related to the room service. And then we're going to do the same thing for the off service. And we will learn the, the, the gruff DO files and then add all of that automatically, automatically inside the schema dot graph TO file. So here, let's start, let's start by defining the room type. So let's create type and name it. Room. And ROM is going to contain, of course, an id of type int and it's required and an array of users. So we have to Use the user type. And as you can see here, I don't have an error because we already used the user type or declared these are type here. And like I said before, we're going to merge the two files, the Earth graph Gill and their own GraphQL inside the schema, that GraphQL file. So we will have access to the user type. So here let's define the room with the user and the messages. Then the messages, it's going to be an array of message object. And we have to define this above. Here. Declare another type, name it message. And its message is going to have a form field. And it's the ID of the user. So we can know who sent the message and the content of the messages. And this one is of type string. Now, in order to send a message, we need the message itself. It means the content. And also we need the bromide D and then save that message inside the room. The message, the message is array. Then all the users inside the user's array is going to have access to this message. So if we have here two users, User a and User B, the message from user a is going to be received to the user B. And of course, both users, it's going to have access to the same message. So let's create an input here, input type and name it, send message input. And we need the message of type string, and we need the room ID of type int. Now let's create the mutation that will accept this input. So here type mutation, the first mutation is the sand message mutation. And here, so MSE is, stands for Message. And here we will accept an input. You can name this variable whatever you want. I like to name it input. So here, this input is of type sent message input. And we're going to return back the rule. Now, let's save this. Of course we didn't finish, but I want to create the orthographic DO file here. Yeah, so let's create a new file inside the folder and name it earth dot GraphQL. And here we're going to copy all of this inside the the GraphQL schema and make sure to cut it. And then save this file and return to the autograph Gill and paste all of this here. Now, we should not add the schema here because this will break our GraphQL endpoint because we're going to define this inside of the schema dot GraphQL file automatically. So let's remove it. And safe also makes sure that inside all the subgraph kill fails. We have a mutation and a query and make sure both of them are capitalized. So also inside the wrong GraphQL have mutation. And then we will create the query and we should name them in the same way we did inside the Earth GraphQL. And you can change the name here. Yeah, because it's not, it's not about the name but it's spot having the same naming. So you can have this like this. And in this case you have to change the room GraphQL notation with a lowercase, lowercase m. But I don't want that. I want a uppercase M, so I'm going to change this as before, and that's it. The next video, we're going to write the logic that will handle the merging of these two files inside the schema dot GraphQL automatically. 28. Auto generate and merge schemas: Now let's create the file inside the source folder and name it, generate the schema. The Ts side here we're going to write the logic that will merge all the subgraph your schemas into the schema dot GraphQL file. So the first thing we have to do is importing all the files that ends with a dot GraphQL from the source folder. And for that we have to install a new package. So open your terminal and run the command npm, install the package globe, and also installed the types for that package. And run this command. Alright, now let's close the terminal and go back here. And let's start by importing the globe package. So here, globe from glow. So globe is actually a function that we can call and specify the path of our files that we want to search for. So for us, we're going to search inside the source folder and inside any folder, and then any file that ends with GraphQL. And then here we have to define a callback that will accept an error and files. So if we have any error, we're going to throw an error, throw new Error, or throw just the, let's continue. First thing we have to delete the existing schema dot GraphQL file using the unlink method from the FS Beckett. So from the file system packets. So that's important. The unlink from not only us, but fs promises here pharmacists. And we have to wait for a link and then delete the schema dot GraphQL. All right, now let's declare a variable and name it types array. Force is going to be of type array and it's going to hold strings. So he's going to hold all the schemas as strings. And that's initiated to an empty array. And then here, Let's read all the files and push them as strings into the types array. So for that, we have to loop through the files using the for each method. In here, take each file and extract the schema from the file using another method from the file system package, which is the read file sync. So we're going to read actually a file. And here let's pass the file here. So this file is a path or just the name of the file here is the path of the file. And that's actually change it to file path here. File path, in here, file path. And here we have to define the encoding because we have to extract the schema as a string. So let's encoded to a UTF eight and then take the schema and push it into the types array. So types array, push the schema. Now after we do that, we have to create another variable and name it type deaths. And here we have to merge all the draft your schemas. So all the strings inside the types array into one file. And for that, we need the merge tool from the GraphQL tools packets. So let's head over to our terminal and style the GraphQL towards beggars NPM. So at GraphQL, dash tools and then slush merge. Alright, let's close the terminal and go back here. And let's first import the merge tool from the lower spec. So import, import nourish type devs from the GraphQL. Then tools than merch. And we're going to use this method. So let's copy the name here and paste it here, and then cite it. We're going to pass the type survey. Now, this method is going to generate a document note, but we need to, in order to append something to the to a file, we need to generate a string. So for that, we need another tool from GraphQL. So import from GraphQL another method called print. So the front is going to take the top typedef and converted to a string. So say here, this put this inside the plant methods. Now the type, this is of type string. So let's append the string inside the schema dot GraphQL file using the append method from the FS baggage. So make sure to import the here. And now let's use it and mentioned the schema dot GraphQL. And here we have to add the types that we can append them into the schematic graph Gil file. And this function also accept a callback. So let's define function and we'll accept an error. And then if we have any errors, we're going to throw that better. Alright, now, if we finished, I want to see a confirmation message into my site, my terminal. So I'm going to console log the GraphQL schema generated message. Or maybe let's use the console dot info. And before appending to the schema, that GraphQL file, we have to create that file because here we are. We're going to delete the schema.gov kill. So to create a file, we have to use the right file sync method from the FS packets. And again, make sure to import that from from the FSLR package. Here we will also add the schema dot GraphQL. So this is a path for the schema graph guilt. And when mentioning just the name, we're turning this method that the schema graph Gill actually exist inside the root of this project. So here, schema graph. And I want to append to this file a message saying that this is a generated schema. Then here, let's say do not. Right? Now, Let's also a new line. And here we need to add a flag at an object and inside that div like option. And because we're going to append something to this file, we're going to use the a flag for append. And also because we're deleting the schematic GF q five here, we have to use the plus sign to create the file if it doesn't exist. Now let me adjust the code here. And Let's also add another line here. Backslash n for new line. Now we've finished creating this script and we're going to execute the globe function as a command from the package.json file. We have to do that before the force-generating the types for our GraphQL schema. So before this command, we're going to run note and then refer to the dist folder and to source generate schema that Z, S. And here in the compile command, we're going to compile our code, and then we're going to run degenerate command. So here, npm, run generate two and science also here. And then save. Now, let's open the terminal and run degenerate come out. And of course we need to compile the code first. So let's run TSE. And then let's run the npm run generate. And here we go, we have the GraphQL schema is generated message. And now we have to parse the schema graph girl and add all these generated TypeScript types there. Now let's check the schema that golf gear. And here we go. We have our generated schema. We have our types and inputs. And here the mutation, you can see that we have the off mutations, the sign-up and sign-in. And we have the Mutation, the send message mutation, automatically added inside the mutation type. And of course we have only one query, the current user query. And you can see also here that we have the schema also generated here automatically. Yeah. And remember when I said that we're going to get access to the user here, if you didn't understand that. I mean that when we generate the schema, the schema, the GraphQL, we're going to have all the types in one file. So we're going to get access also to the user type. Yeah. So it's okay to use the user types inside the room dot GraphQL file, even though we didn't declare it here. Now, in the next video, we're going to create the room resolvers. And then inside the module, the ts file, we're going to merge it with the resolvers. 29. creating the room resolver: Now inside the rooms folder, Let's create a new file and name it from that resolvers dot ds side here, Let's export a constant with a name, room resolvers. And this constant is going to be an object of type. Result looks. It's important that from our generated types. So a port resolvers from go out When level and select these integrated folder and then select the resolvers. Dash types file are now inside here. We're going to define the mutation. And we only have one mutation, which is the send message mutation. Now because we didn't create the entity, we're going to send back a manually created data. Here, let's define first the sand message station. And we have the parent, have the input and the context. Alright? Now, only authorized users can set message. So let's check if we have an authorized user by checking the contexts that authorized the property. And then if we have force here, we're going to throw a new GraphQL error and make sure to import that from GraphQL. And then going to send back and unauthorized method or I message. So an authorized message, and that's an extension. So here tensions. And we're going to send the unauthorized coat here. And for rised. And now let's send back a room object. So let me check how the object looks like. So we have an id, users messages. So let's add that. All of that return id one. And for the users, we have to create an array of users object, but we can just send back an empty array and also the messages array. But that's a sand bag, just one message here. Let me check how the message looks like. We have from and content fields from sand object from, let's say one and the content test message. Alright, now let's save this resolver file. Or actually let's use the input for the message object just to make sure that we can be the client data. For the content, I'm going to return the input dot message. And here we have the message, either a string or undefined because we didn't add an exclamation mark here. So let's do that. Save. Of course we have to generate the schema again. So let's run NPM, generate npm, been in, right? Alright, now we have generated the schema and the types. So let's go back to normally servers and we can see that the error has disappeared. We can remove the question mark from here. And the message is now only of type string. And here inside the ID, we're going to send back the input that room ID. Because this is a room upset. Yeah, let's save this. And in the next video we're going to merge. The author is over and the room resolvers here inside the module.js file and then test the GraphQL endpoint. 30. merge resolvers: Now in order to merge the resolvers, we need another tool from the GraphQL to slash merge packets. So on the top of this file, let's import the new tool, nourish resolvers from GraphQL, dash tools that smells package. And we also need to import the room resolver. So here, rule resolvers from the rooms folder and from the room resolvers file. Alright, now, in the bottom here, we're going to use the merge resolvers function or tool inside the app module class. So let me cut this and then use the merge resolvers as a function. And this function accepts an array of results. So I'm going to add an array and then paste the authors office here. And you can see that the error has disappeared because the merchant resolvers will return the resolvers type. And here we can add many resolvers as much as we want because we're accepting an array. So let's also add the room resolvers and save this file. Now, let's check if we still can run our PI and that we didn't break anything. So let's open the terminal and run the npm start command. First. Let's make sure that we have a running database. So using Docker, that's one. Then this dash or M for removing the container once we finished working with it, then TI for terminal and direction and then name our message out DB image. And don't forget to expose the port 5455 and the 5432. And let's run this command. Right. Now. Let's go back here and run npm start. This command is going to generate the schema first and then generate the types and then one, the API. But first, we're going to compile the code and then run the incinerate command, and then run our API. We have here GraphQL schema generated. We have also the types. And now we should get the success message. Now, let's open the sandbox. Sandbox and let's first sign up. So here I have the sign-up mutation, I have all the inputs. Let's try to sign up. As you can see here, we have the id one. And that's because every time when we close the database and rerun it again, we will get a fresh database. Yeah. So let's take now the JWT token and go to the settings and add the authorization header there. Here, authorization or the JWT token, save. And let's now run the sent message mutation. Let me clear all of this. And let's go back to the mutation. And sand message, or the send message predation at all. The results are the fields. Here. We don't have users, but going to add the ID there. And we're going to get the from, from the message and the content. Now for the input, Let's clear all of this first and then add the message and the room ID. So the message here, that's the message. And the room ID. Let's say, Well, of course we don't have room ID table, set the database. So let's send message. And we should get back. And object of the room ID with id1 users an empty array. And we have here our message with the message test message straight here. Now, everything is working. We still have to create the room entity and finished the room resolvers. 31. creating the room entity: Now let's create the room entity. So inside the rooms folder, create another folder and name it rule. And then side here, create another folder and name it entity. And then finally let's create the room dot entity that yes. So let's start by Export and defining a class with a name Rome. Then we have to use the entity, the character from tape around, support entity from type or N, and use it for this class. Now inside here, we will start with the ID. And again, we have to import the primary generated column, the character for the ID. And here it's odd that the character, then we need an array of users. So here let's add users and define it as an array of user. And we have to import the user entity from the user, that entity dot ds. So here, user from go back one level, two levels, and three levels. Side The off and sad user folder. Select the inside the entity folder. Select the user, that entity file. Now, the users are a, is a column, so we need to import a color and the character from type around. So here Carlin, and use it here. Now for the users column, we're going to create a many-to-many relation with the user entity. And for that we have to import the many-to-many, the character from tape around and use it here at many, many. Now we have to define the type of the relation, and in our case, it's the user entity. So here we have to add a function and find or return the user entity as a type. Now, in order for this to work, we have to add another character, the join table to Garreta and use it here. So the join table, the character is going to take the IDs of the room and the user entities and save them into one table. Now, we only need to use the many-to-many relation in one side of the relation. And this is called a unidirectional relation. If you want to create a bidirectional relationship, you can go to the user entity. And inside here you can create another column and name it rule, and use the many-to-many the character. Now here we have the room entity. And this should be an array. And use the many-to-many to character here and define the type. So here we're going to get the room entity. And also here we need to add another function where we have to return the property that owns the other side of the relation. So in our case, aside the room object, we're going to get the other side of the relation from the users property. And we should do the same thing inside the room entity. But for the join table, the character, we should only use it in one side of the relation here. So here, let's do the same thing, just an example. So here the user and then return, returned user dot room, because the room property owns the other side of the relation. And should, it should be rooms, not room here. But again, it's just a example. Yeah, we're not going to use the bi directional relation here. We will only need to the union relation, uni directional relations. So let's study this and save it, return back to the user entity and remove all of this. And make sure to delete any input statements of the rule entity and close this. Now we still didn't finish because the Postgres database does not support arrays. Yep. And for that, we need to use a very unique type of JSON, which is the JSON B. Now the datatypes Jason and Jason B, are almost identical. The key difference is that JSON data is stored as an exact copy of the json input text. What is JSONB stores data in a decomposer. Binary for that is not as a string. Yeah, like JSON, but as a binary code. And that's what the binary stands for. Our ADB stands for, it stands for a binary. Now, this is the only way to work with arrays with Postgres. So we have to do this. You have to use JSON v rather than simple arrays are just simple JSON. Now I'm going to add an option here and say nullable, false because I don't want to get a null value here for the users property. Alright. Now we still need the messages. So let's add it here. And it's going to be of type message. And we can import that from the generated types. Make sure to change this. Go out two levels, think of three levels. And here, let's make this an array. If you hover over this type, you can find that we have the content and the form as required properties. And we have here the type name, which is not required. Therefore, we can use the message type here. Yeah, it's not the problem. Now. Here, let's define a column. A column. And we have to use the adjacent began because we cannot use simple erase. And I want it to be not nullable. So I'm going to add nullable equal to false. And safe. 32. creating and updating rooms : Now inside the room folder, let's create another file and name it room dot service that yes. Here let's export a class room service and thus create the constructor. And here we're going to create the room, our repository. And it's going to be of type repository. We can import that from tape around. So import repository from type around. Here we need to add the room entity as a argument here, Rome. And that's important that from the entity. Now let's define the method that will create a room for us. So here, acing, create room. And this method will accept an argument of participants, which is an array of users. So here, array user, and this is the user entity. So we need to import it from here, port user from go out two levels and then select the oath folder. And from there, the user folder, the entity and the user entity file, not only the participants here, we also need the message. Because when we are going to create a room, when the user tries to send a message to another user for the first time. So here the message is going to be of type message. And again, we're going to import that from these generated types. So here, Import message from out to a level, two levels. And then Saturday generated folder, select the resolvers types file. Now here we're going to create a room with the repository repository and where they create methods. Now it's true excepts users. So the users or the participants, and also accepts the messages array. So because we're going to create a new room, we're going to add the message manually into an array. So we're going to get an array with one message. Alright, now we have to return a weight, this dots room repository that save and pass the room document. Now it seems that they have a typo here in the repository. So let me fix this. And I'm going to use multi-select and change this to maybe a repository right? Now let's save. And now we have to handle the case where we have, where we want to send a message to a specific rule. So here let's create another method. It's going to be async again and going to choose the name, add messages to roll. You can choose the sand message name. But I want to be very clear here that we're going to send a message to a room, and here we're going to create a room. Yeah. So now to do this, to send a message to a specific room, we need the room ID, of course, of type number. And we need the message of type, message. Here, message. And now sides here. We're going to use the Query Builder. And that's because we have to deal with Jason be arrays. So if you can remember, we define the messages column as JSON B. And because we have here the array sign from TypeScript is going to be of type Jason be array. So the only way to deal with Jason be arrays is by using the query built. Now let's define Query Builder here. This dot positively our own repository. Create Query Builder. And here let's create a weight Query Builder. Update. It goes, we're going to update an existing room and then add the new message into the messages array. So update, we need the room entity here as type and the property that will be updated inside an object. So we're going to update messages and we're going to use very specific and unique way to update this property. So we're going to use a method or a function to return a query. In this query will have the messages property name and then add 2 bar here. And I'm going to explain this just in a second. Yeah. And now let's add quotation marks. And inside here we're going to add the messages as a JSON string. So we're going to use the JSON stringify method and pass the message. And then remember that we have to add messages as Jason beat. So we're going to convert this to Jason V by adding two columns. And then, right, Jason, be like this. So this whole string is a Postgres query. And when we add the two columns and the Jason be like this is going to be parsed by Postgres as a query. And Postgres will handle the converting of this string, of this JSON string, two adjacent beat. And the 2 bar here means that we're going to append this JSON B string and to the messages property. Now by using the Query Builder in order to add a query with the update method, we need to return it as a from a method. Okay, now, let me adjust this code and continue with the Query Builder. So we're going to update a room, but we have to identify the room that we're going to update. And for that, we will use the Where method. And this method is going to add a where condition into the query builder and create the where condition. We will add a string here and say that we're going to update a room where the ID equals to variable ID, and we can define that variable in another argument of this method. And inside an object, define ID, and it's going to be set to the room ID. Now, we still need to execute this query using the execute method. And if you hover over it, you will find that this method is going to return a row database results, but we need to return a room type. And so this execute query execute method, it's not going to work with a TypeScript environment. Therefore, I'm going to return a weight and search for the updated document. So there's the room repository and then use the find one method. And I'm going to search for a room with or where the id is equal to the room ID. And also in order to return the relations, we have to add the relations property and specify an array or an array of the relations that we want to fetch. In our case, we only have one relation, which is the user's array. And that's it. This is how we can update a, an entity and return it with the Query Builder. 33. CreateRoom resolver 1/2: Now, before we start using the room service, we have to import the app data source and create an instance here and pass the room repository. So let's first import the app data source from two levels out and then select the data source. Now here, we have to export a constant and name it room service, and create a new instance of room service. And pass the or use the app data source and then dot Git repository and pass the room entity. And here change this to export. All right, let's save this and close it. Go back or open the rooms of resolvers and as import the room service service from the room service file. And here let's set the message or send message resolver. Let's delete the return statement. And we're going to return the weight. The rooms service that message to Rome and pass the room ID first from input through my d. And then we need to pass the message. And the message is an object with property content. And we're going to get the content from input that message. And also we have to add the from property, which is the ID of the sender, which in our case the current user ID. And we can get that from context, that Korean user, that user id. Now we finished from the sand message resolver. Now here, let's add a comma and then create the create room resolver. So Async, create room, then for the parent. So here create room and I'd parent and then add input and the context, context. Right? So here we have create room, but we're getting these errors because we didn't define the creator of mutation inside our room GraphQL schema. So let's do that really quick. Here. Let's create another mutation and name it. Create room. And input of type. Create room, input. And let's define this here. Input, create room input. So I have here autocomplete. Very annoying. Let's fix that. And instead they create room in book. We're going to accept a message field with a type string and a receiver. The type int guys are going to get the ID of the receiver. Now here we have to return back the return type. So I'm going to return the row and then save. Go back to the room resolver. And for that we need to generate the schema or the types from the GraphQL schema. So open your terminal and run npm, run generate. Right now, I think we forgot to add. Very important thing is that our schema here, which is to make the create room input required. Otherwise you will get TypeScript errors when trying to use the use the create ROM input. So here, let's run this command again and clear this or just remove the terminal. Go back here. Now, first thing we have to authenticate the user. So I'm going to copy all of this and paste it here. Now, we have to check if we already have a room that contain the receiver and the sender. And for that, we have to create another method inside the room service. So let's open room service and here, create another async function and name it, find, boom, with a user's Id. Alright, now we're going to get, or to search for user for a room with the receiver ID, type number and the sender id of type number as well. And here we're going to use the Query Builder in order to fetch the users relations. So let's create a constant here and name it Query Builder. And then use the room repository to create a new query with them. Let's add an alias here to refer to the room entity of room table inside a database and create a Rooms constant because we're going to fetch all the rooms that contain a user with the ID sender ID. So let's do that. Await query builder. Then in another line, let's select everything and then use the inner join method to join all the relation inside the room dot users property. So here let's find that the users, then we're going to add a, an alias to refer to the users relation. And I'm going to choose simply the letter U here. And then we're going to add a where condition satisfies condition. We're going to map through the user's relations array. And that's by adding a double quotation marks like this. You aureus, and then add another double quotation marks with a dot here to select the ID. And then check if the ID equals to the variable sender ID. And here we can define that variable sender ID. And then we're going to use the get many methods to get many rooms. And then we're going to use JavaScript to return a Boolean here, return and then add double exclamation marks here. Then rooms at a question mark because we can get null. Then sum is the sum method to check if some rooms has a very specific condition which is rounded users. So we're going to check if it's one of the rooms. And inside these users property, we can find at least one user that has an AD that is equals to the receiver AD. Alright, now we have here to some methods, but it's a gay. And now we can prevent creating multiple rooms for the same users. 34. CreateRoom resolver 2/2: Now, if we have a room that has two users with the receiver ID and center ID, we're not going to create a new room for them. So let's create a constant here and name it. Room has users. Then use the room service that find room with user ID or users ID. And then we have to pass the receiver ID from the input that receiver and the sender ID from the contexts that Korean user, that user ID. Alright, now let's check. If we have a room that has users, then we're going to throw back in YouGov KL and say that receiver already exists or just room already exists. Yeah. So here room already exists. And that's it. Now, if we didn't find a room where the receiver and the sender, we're going to send or create the room and then send the message. So let's return 08, the room service that create row. Now this method accepts a participant's array, which is a user array. So we have to fetch users from the user repository. And for that, we're going to create another method inside user service that will return multiple users by their IDs. So let's create async method and name it find by ID. Because we're going to a, pass an array of ideas, going to name There's find by ID in array. And here at ideas, arguments of type, array of numbers. And return. Await this that user repository dot find by ID that exists inside the ID's array. And for that, we're going to use a method from type of RAM called in method. So make sure to import that from type ramp first, then the ID's array. And the method will find all the users that has IDs that exists inside the array. So we can name this method find by IDs rather than find by ID in array. Alright, now let's save the user service, close it and go back here. And we're going to create a participant, survey. Participants. And going to use the user service. First that's imported from the off folder and from the user service file. And then here, await user service that find by ID. And we're going to pass an array with two IDs from the contexts that currentUser. Going to get the user ID. From the input. We're going to get the receiver ID. Yeah, Then here, Let's pass the participants and the message. So the message has two properties. First one is the content. Can get that from input that message, and the from property that represents the receiver or the center array ID. And we can get that from currentUser dot user ID. And that's it for the create room resolver. 35. Creating getRooms resolver: Now we're going to create a query that will fetch all the rooms from the database. So we're going to start from the room that GraphQL schema and define a new query. And name this query, get rooms. And it's not going to accept any inputs, but it will return an array of objects. Let's save this GraphQL schema and generate the types for the resolvers using the NPM run generate command. All right, close the terminal in the room, that GraphQL file and then go back to the room resolvers. And here under the mutation, going to define a query. Then define the get Rome's resolver. And we're going to get a parent and empty input and the context. And here we have to authenticate the user. So let's copy this and paste it here. Now we need to create a new method inside the room service that will fetch all the rooms for us. So in the top here, create a new async method and name it, get all groups. And we're going to get all the rooms for a specific user. So here we will accept a user id of type number. And we're going to use the Query Builder in order to fetch the users relations and then return all the rooms that has a user with this user ID. So let's first define the query builder from the room repository. Create Query Builder, and choose an alias room. And then here let's use the Query Editor. So going to return 08 Query Builder. And then we're going to join the users tables inside the room that users property of the room table. So here is inner join, join the relations tables and select rounded users. And we're going to refer to the users array with the letter U. And then here we're going to use the word condition. And we're going to select all the rooms that has a user with an ID that is equals to variable ID. We can define the variable ID here, SAT, this object ID equals to users ID. And then we will get many, many rooms. So we're going to use that, get many. Right now. Let's save this and go back to the room resolvers inside the get room query. We're going to return a weight. Room service, gets all routes and pass the user ID from contexts, currentUser, then user ID. 36. Test graphql enpoint: Now it's time to test our APIs. So make sure you have the Postgres database running. And you can do that using this command. Make sure to expose the correct ports. And then come here and run npm. Run start. Alright, now let's navigate to a polo sandbox. Make sure to sign up and copy the JWT token inside the connection settings and inside the authorization header. Now, silent mutation, we're going to test the, the send message mutation. But first we have to create another user in order to send a message to. Yeah, let's here. Resent the signup mutation with user to the email and the firstName and ran sign up. Now this time, we're not going to copy this JWT token inside the authorization header because we have to authenticate ourselves as the first user or one of these users. Yeah. So here we have the user with id2 and we're going to send a message him with the, with his AD. So that's clear. This remove the signup mutation and remove the input. Click on Send message. And the send message mutation. We're going to get the id users and the messages of the room. So I said the users. Let's take the first the first name, and the ID. And then for the messages that's fits the form field or from field and then the content. Alright, now for the inputs, we have to add the message and the room ID. But we don't have rooms yet inside our database. So what we have to do is we have to create a room before sending the message. So let's add the create through mutation and add. Let me clear all of this first. And then we added create room or the, all the fields here. And for the users, you will get the id and the firstName, the messages we're going to get it from. We don't care about all of this from just message. Even here we're going to send a message to a user. Yeah. Let me check what fields we have side, the messages have content. Now let's go back. And the inputs. Let me clear all of this message and add the receiver. The receiver is going to be user with id2 and the message just as simple text, like text message. Now let's send or create the room and send the message. Alright, we have here the room object with ID one. And we have the array of users. Yeah, and we have the ID of the user one. Yeah, firstName is one, and the second user inside this room. So these two users now they can send messages to each other. We have here the messages array with just one message. And this message has been sent by the user with ID1. So the user one. Now, if we try to create another room with the same receiver ID, we should get an error saying that room already exists. So let's see if it works. Alright, so here we have the message room already exists and we are safe to go. So the next mutation that we're going to test, it is the sand message. So let me clear all of this input and add the send message mutation. We're going to get the idea of the room, the ID of user, and the first name of the user. And then we're going to get also the messages here. Going to get the from field, the content field. And then for the inputs, we have to add a message input, iran my D input going to send a message to the room, ID one. And let's add a message, another test message, the send a message. And here we go. We have the same room, a room document with the same users. And here we have added another message to the messages array. And user2 also can send messages to this room, but we have to sign in as user to get the JWT token added to the authorization header and then send the message. Let's do that very quick. So a sudden mutation. Let me clear all of this. And at the sign-in mutation, going to get only the JWT token. So here, remove this JWT token. For the inputs, we need the email and password. All of this. So the e-mail of fuser two is user to add email.com and the password is password. Now let's sign in. And remember we're going to send a message to room ID1. So let's take the JWT token added to the authorization header. And safe. Now we are signed in as user to, let's go back to the mutation, remove the sign any mutation and sign in inputs. And here are the send message mutation. Going to get the idea of the room, the idea of the users, maybe also the firstName. And going to get all the messages. Alright, let's add the inputs. The message input, the room ID input. So I said that we're going to send a message to my d1. And the message is message from user to user one, send messages. And here we go. We have this same room ID, room document to the room ID one, and same users and a new message inside the messages array. This is how we can send messages using the rooms concept. 37. Implementing validation with class validator: Now we're going to add validation to our project. And for that we're going to use the class validator packets. So Sage or a terminal npm and style class validator. And the reason why we're going to use the cluster the data, is because the classified data users decorators. And we're going to use the characters Class validator inside the entities to check if we have e.g. a. Valid email or to apply a certain conditions to the password. So first, to validate an email of the user entity, we're going to import from the class validator. Going to import the character is e-mail. So this is a decorator that we can use. Bake other decorators of diaper around here. Apply the decorator to this property is email. And you can see inside the definition here that this decorator checks if the string is an email. If given body is not string, then it returns false because any man should be always a string. Now for the password, we're going to validate the length of the password. Yeah. So here we need another, the character which is the Min Nan. Then apply it on the password property. So here at length. And the minimum, then for the password is going to be six and save the file. Of course you can explore more. The characters inside the cluster meditator just write is like this. And you can find a lot of the characters that to validate a lot of things like uppercase, like checking if a property is and URL, or is an array. And a lot of things like even it's empty or not, or it's uppercase or lowercase. And lot of things, yeah. So check all of that and play around with the class validator. Now we're going to learn how to handle the validation. 38. Catch validation errors: Now all the validation the characters are going to be executed when we create a new entity. And before saving that entity into the database, we're going to use another method from class validator to catch all the validation error. So let's head over the user service. And here where we created a new user entity, let's first import the method, validate or reject from the class validator. And we're going to use that method before saving the user entity. Here. Wait, validate or reject. Then we're going to validate the user entity. And then we're going to use the catch method to catch the vibrations or the validation errors. So here we're going to define a callback that will catch the errors of type validation, validation, error array. And we can import this type from the class validator. So here, port validation error from class validator and continue with the callback. So we're going to throw new GraphQL error if we had any errors. Yeah, so important, the GraphQL. Graphql and going to send back a message validation error with extension. Extensions. And we're going to send back all the arrows. Yeah, with the code that user input. Now we have two problems here. The first one is that the password is going to be harassed. So if the user send a three characters password, we will get a, we will validate only the hazard password, which is a long string password. Yeah. And the second problem is that even though we're throwing an error here, we will still passing a running, executing this line here, we will still saving the user. So to prevent all of that from happening, we're going to use the then method. And here inside a callback. We're going to take this nine. Added here. Remove the password from the create method, and just give the aura. Just leave the sign-up input like that. And we will change the password here. Make sure this method is async because we're going to use a weight. Now when we generate the password, the password, we will take the user entity and change the password to be equal to the hash password. Alright, now we fixed problem one. Now for the problem to, we're going to return the user. We're going to save the user and return the, save a document from here. And then we will get a result here. This result is the same that user can see here. Result is of type user because here we returned the user from there. So we will just use the return statement here. And that's it. Or actually we did a mistake here. We should not use the cats method before the then method. Yeah, So the catch method should be the last, the last method. So here, catch any errors. So if we have any error here, we're going to send back a graph earlier. But if we didn't catch any errors, we're going to execute this, go back. Alright, now we can save this file and then run the server from the terminal. So here, I already have did that. And you can see that node man is restarting all the restarting the server because we changed the file. And now let's test our API inside the Apollo server, I mean the affordable sandbox. So here we have our signup mutation. So I'm going to send a valid email and a valid password. So I'm going to send three characters password and execute the signup mutation. And we should get a validation. Here we go. So we have to get two arrays here and say the errors array have to object, means that we did get two errors. The first error is for the e-mail. So here property, email. And you can see inside the contracts we have is email property. And with the message, email must be an email. And for the property password, you can see that we have the message password must be younger than or equal to six characters. So now we know that our validation is working. You can add more validation using the class validator. You can now validate the room entity and play around with the clustering data. Now, before ending this video, I want to note that if you close the Postgres database by hitting Control C, like this, you have n and then you rewrite it again with the docker run command. You have to close the GraphQL server by the Control C and rerun it again. Yeah, rerun it again when now the Postgres database is ready for accepting connections. Otherwise, you'll get many errors and you will not be able to work with the database. 39. why we should use ScoketIo: Now we can send messages between users, but in order for a user to see the latest message, he has to reload the browser or e.g. here, we're using sandbox. We need to fetch all the rooms in order to see the latest messages sent by the participant of that rule. And you know that users will not appreciate that because all messaging app now have some sort of real-time data transfer mechanism so that users can get and read new messages in real time without light, refreshing the page or closing an app and reopen it again in order to fetch the rooms and getting you the latest messages. And that's the feature that we have to implement in our application. So we're going to use Socket IO, a very popular library that enables real-time communication between web clients and servers. You can navigate to socket dot io and read the documentation and see some examples. Yeah, but of course we're going to work with Socket IO in this project, and we will start in the next video. 40. Join rooms with socketIo: Now let's start by installing socket IO from MPM. So open your terminal and run npm install socket IO. Alright, let's now open the module, the ts file and implement the socket IO server there. Here let me close the terminal. Open modular tears fire. And the first thing we have to do is import the server class from from socket that IL. Now we're going to implement the socket IO server inside the startup auto method and implemented with the HTTP server. So here we're going to create the A0 constant and create a new instance of server, pass the HTTP server. And now we have to start listening for connections. And we can do that with the on method and listen for the connection event here, connection. Then we're going to add and go back here. That will get a socket. And we will do something with that sort of gets. So in order to be able to use the socket inside all our resolvers, we're going to put it inside the request and we can get access to the request from the ad constant. Then request and create a custom property and name it socket IO, and set it to the socket that we received from the client. Now we have to add the socket IO property to the request interface, and we're going to do that inside the main.js file. So let's open it. And inside it, we're going to declare a global variable or namespace. And we're going to select the namespace express. And inside it we're going to select the interface request. And here we can add the socket IO and make it as not required. And then the socket IO is going to be of type socket. We can import this type from the socket IO package and then save this file and then go back to the module, the ts file. And you can see that the error is, the error has disappeared. Now. Because we're using the rooms concept inside our application, we can do the same thing with Socket IO. So we're going to use the client socket to join all the rooms that the user have. And then whenever we emit a new event to one of these rooms, and of course, I've a socket didn't join the room, it will not get the event. So we're going to do all of that inside the context. And here we have to check if the, if we have a payload. Yeah, if so, we're going to fetch all the rooms from the database. In order to be able to do that, we have to create a constant here and get the updated source instance. So here, create our data source. And we're going to use it to fit all the rooms. So here at Data Source, dot manager, going to use the manager and then Git repository. And we're going to get the room repository. So import the room entity and use it here. Room for that from here. And port the room entity. From the rooms folder inside the room. Select the NSAID entities like the room entity. Now here we use the room to select the room repository. And then we will use, we will create a query builder, an alias for the room. And then we're going to select all the rooms that contain the user ID. So for that, we need to use inner join to join all the users tables from the Rome dot users and add a alias for the users array. And then add a where condition here and loop through all the users array and only select everyone with a user ID equals to the ID variable. And we're going to get the ID of the user from the payload, that user ID. Alright, now we will add another method here to get many rooms. And here let's create a constant and name it Rooms. And wait for the result. Alright. Now here we're going to get an array of froms objects. And then we're going to use the socket IO from the request to join them. So here, Quest Dot socket IO that join. And this method is going to allow us to add rooms to the socket. And you can see here that we can add either a single room or an array of froms. Now, we need a unique reference for, it's true. For us. We have the room ID as a reference, but it's room. It's, it's room reference should be a string. So here we have one string and here we have an array of strings. But as you know, the rooms IDs are numbers. So we're going to convert them to strings. And we're going to create an array of strings IDs. Here, create a Rooms IDs, and then take the rooms array and map through all the rooms and return a string using the literal string, and return the room dot id. Now we have an array of strings. So let's pass it here. Rooms IDs. Alright, now we finished. But here we have an error saying that the payload doesn't have a user ID property and that the payload is of type string or a JWT palette. We can fix that by checking if the type of payload doesn't equal to string. And we have to check if we have a payload. Yeah. Then we can use the user ID property. Now, this is how we can join rooms. The next video, we're going to learn how to emit events to a specific group. 41. Emit messages to a specific room: Now, in order to emit events, we have to use the IO constant, which represents the socket IO instance, and we have to pass it to the return value of the contexts methods so we can use it inside our resolvers. So here inside this object, add A0 and save the model to ts file. Then inside the room dots service file. Here we're going to use the IO instance inside the ad message to room method. So here let's add as an argument of type server and make sure to add the question mark here. Because sometimes it can be known. Now for the server here, can import this from socket IO package. And then after we update the room and add a new message to the message array, we can check here. If we haven't IO, then that case, we're going to emit a new event using the image method. Now this method accepts two arguments. The first argument is the name of the event, and the second argument is any type of data. It can be an array or object, or a string, or even a json. Now again, Jason is just the string. So here we can name the event message. And for the data here, we're going to send an object containing the message and the room ID. Now, in this case, we're going to emit this event for all connected users. But we don't want that. We want to emit this message to a specific rule. So we're going to use another method here before they emit. This method is the method and pass the room ID as a string. So let's use the literal string and add the room ID. Now, we will emit this message, this event, to only two users who have participated to this room. Now, let's save this. And inside the room that resolvers and inside the send message resolver. We're going to pass the IO here past the AL from the context that I0. That's it. Now, let's save this and that's the APR. 42. Testing socket Io server: We cannot listen for events using the Apollo sandbox. That's why I've created a very simple application where we can send and receive messages by listening for events. And all of that logic is inside the index.js file. You can see here that I'm connecting to the server. And here I have some queries and mutations to send the message. And here I'm listening for the Connect event and for the message event. And as you can see here, I'm parsing the data into the HTML document. So to run this server, you have to have an extension called Live Server. So here you have to search for the live server extension and install it into your VSCode. Then you will find you would get an button here. Let me disconnect. Yeah, you'll find a button that says Go Live, click on it, and then you will have a live server. So let me rerun the server and start testing the application. This is it, this is the simplification. I only have a place where I have to put the JWT token and sign-in. Then here we will send the messages. I have two browsers here, so two instance of the same application. Now we need to enable course inside the socket IO server in order to be able to connect using this URL. So copy this. And then here inside the module, the ts file, and inside the Stockdale server, Let's add a new object and set the course option. Set the origin to the this URL, and save it. Then let's go back here and make sure that you have restarted your server. And we're going to get the JWT token from the sandbox. So here, make sure to sign in and then take the JWT token and copy it, and then paste it in one of these applications. Click on sign-in. And then I have signed in as another user and I saved the token. So I'm going to paste it here. Make sure to do the same thing. Click on sign-in. And now let's test the server, go into sand high and it didn't work. And that's because here, alright, we have to remove the sludge from the end of the URL. So let's go back to the module, the tears far. Remove the sludge from there, and make sure that the server has restarted. Let's wait and then test again. Alright, you can see that we are now connected because we have the connected message here. Now, if I click on sand, we should get high here. And here maybe we have to reload the application. So let's copy the JWT token, reload and then click on sign in again. And maybe the same thing here because we have to join to the rooms. And before, I think that we didn't do that in the server. So let's sign in and send high. Alright, we got the same message inside the two instance here that send here like hello. And here we go, our application is working. Now as I said in the beginning of this video, you'll find the source code attached so you can download it and test it by herself. 43. Database migration with typeorm: Now we've finished developing our API, but we still need to handle one thing, which is the case where we want to update our entities. That case, we also need to update our database. So e.g. if you want to change here firstName to only name, of course we need to update our files, but most importantly, we need to update our database tables. Now, if we sold it in push our project including the database into production. So we don't have any importing data. We can shut down the database and rerun it again in order to remove all the tables and create new ones. But if we already pushed our project into production, we have active users, e.g. that case, we should not follow the first approach because we don't want to lose all of our users data. And also it's going to be a big disaster for our app. So what we should do here, well, the app data source, we have this property synchronized set to true, means that we're going to update our database tables every time you make a change to our entities. This substance is going to only change names and types of some columns, but it's not going to preserve any data. So this option is as dangerous as shutting down the database and rerun it again. So long story short here, the only way to prevent data loss is by using something called Database Migration. There is a lot of ways to do that. But with type ramp, we can automatically generate files that contain secret queries that will be responsible for the integration. So in a sense, the synchronize option to false and safe. And you have to make sure that we have a running database using the Docker command. And we have to run our server so we can create the user tables and the bone types. Alright, now let's go out to the user entity and change firstname to name and then generate a migration. So here, name, save this, and let's update the GraphQL schema here from firstName to name. And the same thing, site the user type, firstName, tunic, Save. And here we're going to generate the schema. It failed because we have to generate this came out by ourselves. So here npm run generate and then we're going to run the server again. Alright, npm starts. Now we're not going to update the database because we have the synchronize option set to false. So we're going to wait for the server here, and then we will generate the migration files. Alright, now let's open another terminal. And order to generate the negation of Phi is we have to install that program globally inside our project using this command. Yeah. And sometimes you need to add the keyword in order to gain admin privileges. And if you're inside Windows machine and you have to open a administrator console. So I'm not going to do this because I already on start type ramp globally inside my system. So I'm going to proceed to the next step, which is using the NP x, which is a package that comes by default with no GS and NPM. And I'm going to run tape around using the ts node and CommonJS module for JavaScript. And we're going to run regression, Carlin generate, and specify the location of our iterations files. I want them sites source folder, and inside a Migrations folder. And then we will get files with timestamp and migration keyword. So we're going to get files with timestamp, does regression dot Yes. Okay, Now we have to specify the location of the app data source. So here, source of Dutch data source that yes, that's it. Let's run this command. And here we go. We have successfully generated the immigration fights or one file. In this case. This file is a TypeScript file with a class. And here you can see the name duration and a timestamp. Then here we have two methods up and down. So the add method is going to be executed every time when we run this, every time we run this migration. And we're going to execute this sequel query that will change firstname to name. Now the down method can be used to reverse the immigrations as represented here. You can see the query here that will change name to firstName. So if we change our mind and we want to revert immigration, we can execute the town method. And of course, all of this is going to be executed automatically using the type RAM CLI. Now to run this regression, there is two ways to do that. First one, we can use the same command here but changed. Just a few things like keeping the data source and moving this nine here and change your rate to run. That's it. And we can run the immigration and we're going to get a updated database. Can do that, or you can run the migration inside or from tape around automatically using the data source here. And by adding the immigration, immigration is run property. And we're going to specify where our migrations located. So because tapeworm here cannot run Ts vice obviously. So we're going to point to the dist folder that contains the GS migrations, fats. So here, this and then source, and then inside emigrations folder. And then run all files that has a Dutch migration were gs and ends with the dot js extension. Yeah, so let's save this. And actually it's not migrations, Run button integrations. That's it. We're going to use the immigrations run to specify that we want to run all the migrations when we run this server. So here set to true. Now let's save this and going to see that our server is restarting. Alright, now let's try to sign up. And this time we're not going to use firstName, but we're going to add just name. Right here inside the sandbox, Apollo sandbox. Go to a mutation and select the signup mutation. So here, signup mutation and wait for the JWT token or the inputs. And you can see here that we updated the graph gear, but doesn't mean that we updated also the database. But we're going to check that in just a minute. Yeah. Let's add all of that here. And let me expand this. Alright, choose any email. Email, email.com, lastName, user name, say John. Password. Password. Let's sign up. And we should get the JWT token. If we successfully updated database and we have successfully done that, we have here the JWT token, and we have a user inside our database with the new property name instead of firstName. So let me take if we can return the user here, alright, we can, so let me return all of these fields. And I'm going to sign up with another email may have one user one, and that's it. Let's sign up. Here we go. We have here name set of firstName. So we have successfully updated our database using the immigration. So this is how we can do that. But makes sure to set this to false always. Or it can just remove it from here. I'm going to keep it just to remind you that this property has to be false. And for the immigrations, we need to always execute GFS files. And you can see inside the dist folder that we have immigration folder in here we have two files for the immigration. And that's because I tested this API and try to run the migration. But when we have multiple tiers, migrations files, and you delete them here, doesn't mean that it is going to be deleted side the dist folder. So always make sure to remove the dist folder here and make sure to generate a new one every time you run the API. Otherwise, you will execute all the integration files and you will corrupt your database. And remember also to do the same thing. Site here removed immigrations because we already executed them. But if you want, you can keep the immigrations files inside another location. Yeah. Not not necessarily. Side the project folder. That case, you can use the down method to revert the immigration if you want to do that. Yeah. So for us, it's not a big deal because we're just changing firstName to name. So I'm going to delete this whole folder. And that's it. Now every time when we want to migrate the database, we will get a new files and run them from the type around data source. Now, before ending this video, I want to mention one thing which is if you want to run the migrations using this command, you have to have the migrations property inside the data source, right? And you can add immigrations run or just remove it from there. Does it matter? But order to run this command, you have to have the immigrations property and specify the migrations location. And that's it.