Nest.js Microservices with NATS, SQL, and Docker

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone my name is anen today I'm going to teach you all how to set up microservices in sjs you're going to learn what microservices are how they differ from traditional monolithic applications and how to use a natat server to communicate with each microservice now in order to understand what exactly is a microservice we need to understand what monolithic applications are and in fact many developers like yourself are used to building them already typically when you're building an application you have only one API that has all of your endpoints defined for your front end for example let's say you have a e-commerce website that has to handle user authentication it has to handle payment processing order confirmation and many more domains in your monolithic app your API server will handle all of those API requests it will produce some kind of output and it'll also send that as a response back to the client this means that you have one single process doing all the work for the clients and if your deployed machine that is running the application has limited resources you can start to see performance issues instead of having that single API do all the work you can have each microservice perform the relative task and send it back to the API so that kind of divides the work from having just one single API one single process doing everything into different components doing different things so you have not only one process but multiple processes doing the work for you so I have a simple diagram for you to show you what a traditional API server that handles these requests would look like so you have your clients they will send get requests post requests whatever it is they'll send it to the API the API will talk to a database or some external API some external source it will perform some kind of computational work produce some output send it back to the client now again like I said before depending on what the business logic is it can become very expensive and it can start to bottleneck your application and what you can do is instead of having just one API doing everything for you you divide that into different microservices to handle different payloads so I'll show you a diagram that I drew out of what a microservice architecture can look like now there's no right or wrong answer to approaching this because it really depends on your business needs what you're seeing right over here may not be suitable for a different approach for a product but it could be the right approach for a different product so I'm mentioning that because it really depends on the software architect on how they want to design a system that is scalable and how it would work so like I said there's no right or wrong answer it really just depends on the type of problem you're trying to solve so right over here you can see that I have four clients and there can be as many clients as as you might need or as you might have and we have let's say a graphql server or an HTTP API or even both and they talk with a Nat's server so your clients will send either a query to the graph H server or send an API request to the HTTP API server and instead of having all the work being done on the server what you're going to do is communicate with the microservice now there are different ways on how you can communicate with the microservice sometimes you might actually just use an HTTP client to forward the request to the microservice but in our situation since we are using nestjs they actually Define a microservice and I'll show you where over here they Define a microservice appc application that uses a different transport layer than HTTP so the standard in sjs is your microservices actually don't use HTTP they still use TCP but they use different transports such as redis gats uh rabid mq kofka grpc and many more okay again you could use HTTP if that's what if that's all you need but Nats is also another popular Pro to sending the messages from the API to the correct microservice so in this diagram you can see right of here that the graphql server or the API server can forward that request by simply publishing the message to a natat server now that natat server will receive that message and the payload if there is any data that it needs to process and deliver to the correct microservice so you can see right over here I have a US users microservice a payments microservice and I can also have an activities microservice to track user activity the natat server will deliver the correct message and its payload to the corresponding microservice the microservice needs to subscribe to the N server in order for it to receive those messages and its payload once it does the microservice can process the logic that it needs to do for that domain it can can read and write from the database it can talk to an external API it can do whatever it needs to do once it's done it will send back the result to the API or the graphql server and it'll send it back to the client so hopefully all of this makes sense now what we're going to do is we're going to set up the project so there is a lot of setup involved in this so don't feel discouraged I'm going to walk through everything step by step for all of you so the the way that we're going to set up our project is like this we're going to have a total of three nestjs projects all together we're going to have our API layer so this HTTP API that you see in this diagram we're going to have that API that is going to receive incoming HTTP requests we're also going to have two microservices one for users and one for payments and those microservices are not going to be HTTP apis but they will be TCP based applications that will be subscribing to the natat server so that's how they will receive the messages and the payloads and they will also send messages to the natat server as well if it needs to we're also going to have the natat server that will be responsible for acting like the middleman between the HTTP API and all of our microservice that's how we're going to transport the data from the API to the microservice okay and we're going to have one single database that is going to be shared amongst each microservice I know in the diagram I showed how each microservice connects to its own database typically you can do that but it really just is based on your application sometimes you might have each microservice connected to its own database sometimes you might have uh multiple microservices sharing a database it really just depends just to keep things simple we're going to share one single database for all of our micr services okay we are going to be using a SQL database and I'm also going to be using type RM but you can also use mongodb if you want to as well so hopefully all of that makes sense we're not going to be using any graphql at all and we're going to be combining everything all under one single Docker compose file so we're going to be running everything in Docker because it just makes it so much easier you don't necessarily need to use Docker but I highly encourage you to use Docker for this because it makes it so much easier to run everything all together in one single container okay so let's go ahead and actually get started so what we're going to do is we're going to go into our terminal windows shell and we're going to set up a single folder that is going to host all of our nestjs projects so I'm going to call this njs micr Services tutorial okay going to CD into this folder and then what I'm going to do let me zoom in a little bit is this I'm going to create a new project this will be our root API is what I'm going to call it that's going to be the entry point to our entire application so it'll be our HTTP root API so I'll call this uh let's call this HTTP API Gateway okay we're going to use npm and while this is scaffolding uh we're going to need to set up the dependencies that we will need so luckily we're not going to need too many dependencies the only thing that we will really need to install is the nestjs microservices um package uh the gats package because we need to connect to the natat server and I think that is it okay so I just finished generating the new nestjs project I'm going to CD into this folder and we need to install two dependencies the first dependency is going to be the nestjs microservices package so that's going to be right over here we need this in order to actually set up the microservices and we also need to install the gats package as well since we're going to be using a Nats server to deliver the message to our microservices so let's go back to our Windows Powershell and we'll type npmi njs microservices and then space and then Nets so two packages okay should be pretty straightforward so we just installed both of these packages and then now what I'm going to do is let me open up my visual studio code let me move this over to the other screen okay so there's a couple things that I'm going to do inside this HTTP API Gateway project the first thing that I want to do is I simply want to uh set the port to be a dynamic Port so we're going to use process. env. port and this will be an environment variable that we will set in Docker compose and if the port is undefined we're going to use port 3000 and I'm going to just simply pass this port in and I'll pass a callback function that will log what port we're running on so running whoops running on Port Port so that way we know what port we're running on okay so remember this project is going to listen to a port to take an API request via HTTP we still need to make sure we can connect to the natat server so to do that we need to go inside our root module app. module. TS and right inside the import array I'm going to reference client client module and this comes from the nestjs microservices package that we just installed we're going to call this register method and pass in an array so we need to pass an object in the array and the name you can call this whatever you want I'm going to call this uh Nats service okay we need to set the transport and the transport that we're going to use is going to be Nats so we need to import this from the nestjs microservices package it's an enum and you can specify the transport that you're going to be using so they have different transports but we're going to be using gats so I'm going to select gats okay and then finally we need the options and we're just going to set the servers this is going to be an array of all the natat servers we want to connect to but we we're only going to connect to one Nats server however you could connect to different Nats servers if you want to but just for this tutorial we're going to use one Nats server so we need to specify the protocol so it's going to be Nats and then colon SL slash and then what we need is we need the host name of the NS server now since we're going to be using Docker to host and run the NAT server I'm going to actually set the host name in the docker compos service section I'm going to set the host name to be gats like this however if you're running your natat server on your local machine or if you're running it on some deployed server you need to make sure you have that uh machine's host name okay so for example if I was running it locally on my actual Windows computer I would use Local Host we don't need to specify a port because by default the port is going to be 4222 and we're just going to use that Port but if you did have a port custom Port configured you need to specify this right over here I'm not going to do that CU we're going to use the default Port which is 4222 so we're done with this and all we're going to do next is just delete the generated controller and service file that njas did you don't have to do this I'm just going to do it myself cuz we're not going to be using it at all all so let me delete the service file and uh let's see okay so for now we're done with this root project okay so what I'm going to do next is I'm going to set up a Docker file real quick uh and I'm actually just going to copy and paste this Docker file into this project or the contents of the docker file and it's just going to be pretty straightforward we're going to use node version 18 um we're going to specify our worker our work directory we're going to copy the package.json files and the package lock. Json file and then we're going to run npm install and then copy the rest of the contents okay uh I also need a Docker ignore files so let me also just copy and paste that as well and like I said uh just go ahead and grab the just grab the docker file from the GitHub repository so that way way you don't have to just type all this out or if you want to type it all out it's fine I am going to quickly set up a simple Docker ignore file and just for now I'm going to have it ignore the node modules folder and then you can also have it ignore the build files as well but I'll just leave it like this for now because we definitely don't want to copy over the node modules folder into the docker um the docker container file system okay so let's see the other thing that we need to do and I think you only need to do this if you're on Windows or if you have any issues with um the dockin container not Auto reloading whenever you're making changes to the project so what I'm going to do is inside my TSC config.js file I'm going to copy these watch options settings and this is just pretty much going to use uh Dynamic polling instead of the system native events for file changes so like I said I think this problem mainly occurs if you're on Windows but if you have any issues with uh whenever you're making changes to your code and Docker is not uh reloading the changes it's not restarting the server so the Hot Load is not re working then just add these watch options in your tsconfig dojason file Okay and like I said you can grab this from the repository as well or just look at this part and just type it in okay so this will ensure that we actually can Auto reload our our process whenever we run it and keep in mind that we are also doing everything in development mode so obviously in production mode you wouldn't actually have uh watch options set up this is only for development mode okay so we are done with uh this project for now we next need to set up our other microservices so I'm going to go into uh the Powershell I'm going to CD back into the root directory so inside nestjs microservices tutorial and I currently only have one project where we need to create the other two microservices so we're going to create one for users and one for payments so Nest new users microservice is what I'll call it and we'll do the same setup use npm and then I'm going to do the same exact thing with payments microser service so I I'll get back to you all once I created these two projects okay so I just created both the users microservice project as well as the payments microservice project the same exact setup uh I didn't do anything with it yet I did not install any packages at all so what we're going to do first is we're going to configure the users microservice first and then we'll go over to the payments microservice later so let's go into users microservice directory and we're going to install the same packages that we installed in our HTTP API Gateway so I'm going to install at njs microservices and I'm also going to install gats as well so once we have that installed we then need to uh let's open up the project so let me actually do this let me c it back into the root directory and I'm I'm going to open up vs code in this root directory right over here so that way you all can see all three projects on the file explorer and I'm going to go into users microservice and let's just verify we have our packages installed we have microservices and Nets okay perfect all right so now let's just quickly configure the tsconfig dojon file with the same watch options settings that we put in the API Gateway project so I'm going to copy that over and just paste this inside here and I'll do the same thing very quickly inside payments microservice like that okay we're done with that let's go into the users microservice inside source and we'll also delete the app controller app controller. speec file and the service file because we're not going to need that and let me just delete these Imports and references as well so we need to go inside the microservices main.ts file so inside right over here and remember how I said earlier that the microservice is not going to listen to a port so we're going to remove this part and we're also going to configure this app as well so instead of calling Nest Factory doc create we're actually going to call Nest factory. create my microservice and we're going to type annotate this method with the microservice options type right over here and then we're going to pass in the app module as well and we're also going to pass in an options object so we need to set the transport to gats so we need to import the transport enum and then we need to specify gats since we are using Nats and then we need to connect to the natat server as well so options which is an object servers it's going to look very identical to how we connected it from the API Gateway earlier so if you look right over here it's going to look similar to this okay except we're not doing it inside the app. module. TS file we're doing it inside the main.ts file inside the bootstrap method meod so let's pass in the connection string so Nats protocol and then the host name is going to be Nats and then we just simply do app. listen await app. listen and that's it so we're still calling the listen method but we're not passing a port okay so this will start the microservice and this will subscribe to the NS server and then we can later start to receive messages from the natat server so we do need to set up a Docker compost file so that way we can not only build out all of our uh projects into one single Docker composed script and container but we also need to use it so that we can run our SQL Server as well as the natat server as well so I'm going to go and create a new file inside the root nestjs microservices folder so basically outside of all three of our nestjs projects I'm going to call this file Docker composed. yml and you can just copy and paste this file if you already know how Docker compos works but for those of you who are not super familiar with it I'll still explain everything that we're doing so we need to set up this service right over here so I'm going to go ahead and write services and then Callin and right underneath I'm going to hit Tab and I'm going to go ahead and name the first service API Gateway which will be for our API Gateway project so right underneath we're going to use the build and then we're going to have it Target the HTTP API Gateway project so we need to pass the relative path to that folder so basically this will look inside this folder to look for the docker file and run all of these instructions okay uh the next thing that we'll do is set up the ports so uh since the API Gateway is going to run on Port 3000 we're going to expose the internal containers Port 3000 in the docker compos file and we're also going to map the docker's host Port 3,000 to the internal Port so for us when we run our Docker container in order to actually access the API Gateway we need to go through Port 3000 and that will kind of like forward that to the internal doc containers Port 3000 so we're going to do Port oh whoops need do we need the dash as well so 3,000 colon 3,000 okay and this will pretty much do the exposure of the port for this API Gateway container for you so notice how in the docker file I did not expose the port in the docker file I'm doing it in the compose the docker compose file now I am going to set up a simple volume and and pretty much we're going to mount our source folder into the uh actual Docker container so that way the nestjs process that is running in the dock container we'll see the code being updated and then it'll restart the uh process in the docker container so we actually need this in order for the hot reload to work as well aside from just having our watch options configured so I'm going to just actually just copy and pastes cuz I do have this already set up so what I'm doing here is I'm saying I want to uh let me actually change this cuz this is actually from my live stream that I did uh cuz I did this setup as well live but the folder is going to be httpapi or- api-gateway and we're going to Target The Source folder inside and then we're going to mount it to uh the work directory that we set up in our Docker file so that's user Source app so we're basically mounting it to the docker uh the docker container file system so user Source app and then SL source so whenever I make changes to let's say main.ts inside the docker containers user Source app SL Source folder it will have this main.ts file and it'll also update as well okay I know it can be a little bit confusing but what I encourage you to do uh is make an update to your local main.ts file and then go inside your Docker container uh the file system and look at the changes being updated and that will help you better understand how this mounting is working but don't worry so much about it for now just know that you need this volume in in order for hot reload to work otherwise you're going to have to keep restarting it manually every single time I'm going to go ahead and use the command and I'm going to have it just simply run our uh start Dev script right over here so it's going to run n M Run start Dev and then we're also going to pass in an environment variable by using this environment right over here and we're going to set the name to be port and the value to be Port 3000 just like that and we're done with our API Gateway we're going to do one more for the users microservice so let's just call this users micro service and we're going to follow very similar things that we're doing in in our API Gateway setup so we're going to specify build and we're going to have it Target the users microservice folder so uh we're going to pass the relative path so again this will look inside the users microservice uh we need to actually get the docker file for this so let me go ahead and actually just copy this one and I will go ahead and create this right now and paste this in here and I'll also copy the docker ignore file as well or I'll just create it so Docker ignore so that's dot in case you can't see this it's do Docker ignore that's the name of the docker ignore file and we're just going to ignore the node modules okay so again it will look inside the user microservice and it will look for the docker file in there and run all of the instructions over here okay so remember the microservice is not going to listen to any port at all we actually don't even need to expose any ports for this because it's going to connect to the N server so we don't need to specify any ports but we will uh do the same thing with volumes so that way when we are making changes to our users microservice project it will update on the docker image file system and it will uh it will the nestjs process that is running on the docker container will detect those changes and restart it so I'm just just going to copy this volumes right over here whoops paste that right here and just change the reference to uh users microservice and then this will basically Mount this into the docker container or Docker image file system okay we're going to have the same command so let me just paste that right here and uh I think that is it so I'll quickly just copy and paste this for the payments microservice so we don't have to do this or I'm sorry yeah payments micros service um so that way we don't have to do this later and I'll just change everything from users over to payments and it's going to look exactly the same as users microservice and any other microservice as well that you might set up it will look identical to this unless if there are any other things that the micros office might need then you might need to configure it differently but for now this is what we have pretty straightforward and finally let's configure the the Nats server so we're going to specify Nats so remember how I said earlier that the server's name right over here this is the Nat's service name this is also going to be the host name as well so uh that's why we don't need to worry about the host name over here because it's going to be the same thing and since you're using Docker um remember Docker has like its own network system in place so you actually can't even connect to the Nats server directly by just just passing in like Local Host like this since you're running in the docker container I think there are different ways that you can do it but it requires additional things that you have to do so just to keep things simple we're just going to use the host name of whatever the service name is right over here which is going to be gats okay so hopefully that part makes sense we need to specify the image so Docker will pull the Nats image down and then we just need to specify the ports so really we just need Port 42222 so 4222 sorry not 42222 it's Port 4222 and we'll just map the docker host to the internal Port right over here okay so now all of our services should be able to connect to our Nets server via Port 4222 okay so for now this is all we need later on when we get to my SQL um we'll do that later but let's just keep it simple for now and what I'll do is uh let me just go into uh my terminal and I'm in my root project directory right over here and I'm going to run Docker hyphen compose up hyphen hyen build and let me open up my Docker uh desktop guy and I also forgot that I need to actually run Docker as well so make sure you have Docker running of course okay so I have my Docker desktop graphical user interface right over here and the docker engine is also running so let's go ahead and run Docker compose uh let's see seems like we got this error and it says no such file or directory I think it's complaining because uh one of our projects does not have the docker file and yeah it makes sense because I think we set up this payments microservice and the payments microservice doesn't have that Docker file so let's actually just simply copy it over so let me just copy the docker file and then in payments micros service I'll will paste this right here so now I have the docker file here and I'll also create the docker ignore file or just P you can just paste it but uh since it's just a simple on line of node modules right over here I'll just create that all right so let's try running that command again okay there we go now it's actually working okay it's running npm install for API Gateway uh now it's installing the packages for users and payments okay we'll take a little bit of time because obviously it has to install all the dependencies okay all right and now now let's see okay so seems like everything's good all right perfect so everything is running let's just go into Docker the graphical user interface let's make sure everything's up and running so uh no issues with the payments microservice if there was an issue with connecting to the Nats server it would say right over here uh the that server is up and running you can see the logs um and that server is right over here it's uh listening for client connections on Port 4222 uh API Gateway is up and running on Port 3000 so that is also working as well um let's see I think everything is good just very quickly uh what I'll do is in the users microservice I'll just show you very quickly that if I were to change something in here let's just say console log uh users micro service is running and if I save uh you can see now it auto reloads and it has my changes right over here and remember how I said earlier you can just go into um the files right over here and you can just look in the let's go to the work directory so it's going to be user Source app uh yep right over here and you can look in the source folder and then main.ts and you can uh edit the file over here obviously you don't want to actually edit it but you can see the changes right here okay so whatever you update on your actual local file system it will be reflected onto here because we have the volume set up so I just wanted to very quickly show you all cool so let's actually uh do one more thing if I actually mess up this connection let me just change the host name and it will take a little bit you can see now uh the logs remember how earlier it was logging like a few more lines and now you only see these two things being set up that's because the Nats connection is actually failing because we we obviously don't have this host name correct so you can see that right over here it's failing to connect to the net server so just wanted to also show you that as well okay now that we have all the hard things set up we can actually start to uh set up our API Gateway to take in API requests and then we can send messages to the user microservice so that way the user microservice can perform its business logic so basically we're going to communicate from the API we're going to communicate with the API to the net server and that server will send that message to the micros service so we need to go into our http CP API Gateway project and what we're going to do is we're going to set up um a users module so let's create a new folder called users and let's create a new file called users. module. TS and I'm going to import the module decorator from nestjs common and let me just pass in the metadata for the module so we need Imports controllers and providers as well and then we're going to create a class for users module module like this okay so uh the next thing that we're going to do is we're going to create a user controller so users. controller. TS will be the name of the file and then we're going to go ahead and create a class called users controller and let me use the the controller decorator which is going to be imported from nestjs common and we're going to map this route to be users okay so now we need to create a route to handle whatever it is that we want to handle so we're going to set up a create user route which is going to be a post request so I'm going to use the post decorator and then and I'm going to decorate this create user method okay so whenever we make a post request to/ users it's going to go ahead and call this create user method because this route is mapped to this method right over here and this method is going to need to not interact with a database but it's going to talk to the net server because remember now we're building a microservice architecture so we're not interacting with a database in this controller we're not interacting with anything else but the gats client so what we need to do is we need to inject the gats service into this users controller so remember how earlier when we went into app. module. TS I had this client module. register method being called over here and then we passed in this object that had this natat service defined so we need to inject the natat service into our class right over here so we can do that using the Constructor so Constructor and then inside the Constructor args we can just do uh we can use the at inject decorator and the token is going to be the same name that we provided right over here so it's going to be nsor service all in caps like that and then we just do private and you can call it whatever you want I'm going to call it Nat's client and then the type annotation for this will be client proxy which is imported from the nestjs microservices package so this will now allow you to access the NS client and you can use this to communicate with the Nats server so you can either emit events you can send messages to the Nets server we're going to use two different approaches we're going to I'm going to show you how we can do request and response approach and I'm going to show you how we can use event based approach okay so what we're going to do now is we need to allow this endpoint to take in a request body uh so that request body will contain uh data that is used to create the user so we'll have stuff like a username email um display name we're going to take that request body and we're going to send that request body to the Nets server the that server will then forward that message to its subscribers so in this case we have our users microservice subscribing to our natat server okay so you're going to see how we can forward this message all the way to the users microservice running on its own process okay so let's go ahead and do this we need to register our users module in the app. module. TS file so uh right over here I'm going to go ahead and import users module like this okay and I need to also go into users module and import uh the users controller class inside this controllers right right over here so users controller okay so that way we actually are registering our users controller in our entire gate Gateway application so if you go back into Docker let's look at the uh Gateway application um okay so you can see that we actually have a problem it's complaining about not being able to resolve the dependencies of user controller uh the reason why this is happening is because the user's controller is using the Nets service um but the user's module does not have that uh injected over here so there's two ways that we can approach this we can either copy this whole thing and paste this inside the Imports part uh for the users. module. TS file but we're not going to do that because we are we're going to need to use the Nats service client uh in a lot of different modules anyways so the best thing to do is to create a separate module so we'll do that right now so I'll create a module called Nats client Nats client like this so create new file called Nats client. module. Cs and all you're going to do is just create a simple module so export class NS client module and then pass in the metadata and then Imports and then you're just going to paste in this whole thing let's import clients module and import the transport enum as well and then what you need to do is you also need to add this inside the exports array as well like this so now you can import the n client module in your users modules uh import section right over here okay and then uh inside app. module. TS uh we can just remove uh let's see let's remove this part right over here and now we can see the logs the errors are all gone okay so pretty much this makes it more modular so when we get to working with the payments microservice we're going to create a payments module as well identical to the user module and we can just import the NAT client module and use it instead of having to copy and paste you know this whole client's module. register everywhere okay so hope that makes sense all right cool so we can see that our API Gateway is working just fine there are no issues you can see the users route is being mapped um right over here and you can see right over here if I go into Postman and make a post request to/ users you can see that we're getting a response back it's not doing anything but we are getting a response back so that's good all right so now let's create a dto for our create user payload so I'm going to create a new folder called DT's and I'll create a new file called create user. d.t. TS and dto is a data transfer object it pretty much just is um an object that has the corresponding field mappings so in nestjs it's pretty much just going to be a class so let's create a class called create user dto and we're going to use this class to type anate our request body as well and you can also use the dto to set up a validation so I'll show you how to do that as well so let's just Define the fields that our request body will need in order to create a user so we'll need a username of course we'll need a display name and an email and I'll make the display name optional okay now if you want to have validation for your payloads we can use a package called class validator and class Transformer or sorry two packages so let me go ahead and install that so I'm going to go into my windows Parell let me just kind of exit this process and I'll CD into users or not I'm sorry not users I'll CD into the HTTP API gate way and let me install class validator and then class Transformer okay and this will give us a bunch of different decorators that we can use to Mark each field um as optional or non-optional we can mark it as uh if it's supposed to be a string a number there's different there's many different decorators you can use to ensure that each field is what it's supposed to be okay so let me go and run the application again all right so our project is running again and we need to make sure we enable validation so there's two ways you can do this you can either enable it globally for your entire application or you can enable it for each endpoint I'll just make it simple and I'll go into my main.ts file and I'll enable validation GL globally so it's very easy just go inside the bootstrap method and you reference the app the nestjs app instance and you're going to go ahead and just call this use uh Global pipes and then you pass in an instance of the validation pipe which is imported from the nestjs common package Okay so app. use Global pipes so this will enable validation globally so now we can go back to our dto class and we can use decorators to uh specify which field we want to be required which field that we want to be optional so for username I can use this is uh let's see there should be required is not is not empty I guess is not empty so this will ensure that username is not empty I figured it would be is required decorator I don't know why but there's um let's see let's do is string let's import that is string and make sure that it is the capital is string cuz there's also the lowercase is string like this one and this is is not the wrong this is not the right one for the for the decorator for the field okay um you can also do max length so let's say if you don't want the username to be more than 32 characters you can do that let's import that from The Decorator the class validat the class validator package and then for display name I'll do is optional uh we'll make sure it's also a string and then max length we can set that to maybe I don't know um let's do 64 and email we'll just do is not empty so it has to be required we can also use the is email decorator as well so that means that it will make sure that an actual email is being sent in the payload and we'll just leave it like this for now okay so now going back to our users controller file we can go ahead and grab the request but body that is sent to this endpoint inside the methods arguments right over here by using the body decorator which comes from nestjs common so body and you just call that decorator and just give the name for the method argument so I'll just call this create user dto and I'm going to type annotate it with create user dto like this okay and just very quickly I'll console log this and let me go into Postman and show you how this is going to work so if I try to click Send it's going to throw an error because we are not passing in any user name no email um and it also gives you a message right over here as well you can also provide custom messages if you want but we're not going to do that custom error messages so let's pass in a username oh let me also set the text or set the uh request body type to a Json so let's let's do username Anson and email uh let's do Anson ansen theed dev.com and now we should no longer get any errors and notice how I pass in an invalid email it's going to say email must be an email if I don't pass in the username it's only going to complain about the username right over here so hopefully that makes sense and you can test this out yourself as well okay and of course if I don't want to pass a display name I can omit that from the request body but I'll just pass one for now okay and if you look at the logs let's go into the docker container uh API Gateway you can see that it is being logged right over here so we know that we are receiving the validated request body so that's pretty cool so now let's actually send it over to the users microservice okay so this is actually very simple all we need to do is just reference the Nat's client and call send and we need to pass in a pattern now this first the first way that we are sending uh messages to the net server which will send it to the users microservice is we're using request and response par the request and response approach so I'll actually show you in the docs uh right over here so there's the request and response message Style and there's also event based so we're doing it request and response uh first so this is there's pros and cons to both so for example if let's say if you really need a response back for the client then you would want to use request and response approach sometimes you may not necessarily care about a response you just want to be able to publish messages to the net server and then have the microservice receive that message and perform logic and that's it you don't care about what the client is going to receive as a response then in that case you can use the event-based message Style again uh we'll cover both in this tutorial okay so what we need to do is we need to pass two arguments so the first argument for the send method will be an object and it's going to have this property called command and it's just going to be a string and you want to have it represent an actual command um an actual pattern for the microservice to receive so the way that's going to work is we're going to call this command create user just like this and then I'll show you how we can receive this command on the microservice and then the second argument is going to be the data that we want to pass so pass in create user DT like this all right so for now we're done with this we'll leave it like this for now I want to show you how we can actually receive this message from the users's microservice so let's close this users controller file Let's uh go into the users microservice project and we're going to go into Source folder and I'm going to go ahead and create a users module as well for users microservice okay so let's create that I don't know why my typescript is my typescript server is a little bit messed up okay but I do need to import this from oh actually you know what let me make sure uh let's see njs microservices yeah should be fine so let me just import module from at njs common and then let's specify the Imports controllers and providers which are all going to be erased we're going to go ahead and create a new file called users. controller. TS and now this time since we're inside our micros service this controller is actually not going to be a a regular HTTP controller like we had in our API Gateway project like this one right over here this is actually going to be a microservice controller so let's create a class and we're going to call this users microservice controller just so that way it's not confusing for you all and then we're going to use the we're still going to use the at controller decorator as well which we do need to import from at njs SL common and but this time we're not going to provide we're not going to provide any argument inside the controller decorator you can see if I hover over here it actually tells you that there is two definitions there's an HTTP controller and then there's also a microservice controller as well okay and you can see over here that it responds to requests for the microservice controller it can respond to requests as well as events running over a variety of transports in our case we're using natat okay so hopefully that makes sense so now inside our user microservice controller we can actually begin subscribing to events or messages so the way that we're going to do that is pretty simple first we're going to uh Define a method so I'll call this create user because again the API is handling the create user uh endpoint which is going to forward this message into the user microservice so we need to make sure we are also handling that logic as well at the microservice layer so we want this method create user and then we need to use this message pattern decorator which comes from the nestjs microservice package okay and then you're going to need to pass in the metadata the pattern metadata right over here and what this is is it's going to match whatever you provided as an argument for pattern right over here so notice how my pattern right over here is command create user like this so it needs to match this one as well okay so that way it knows which correct pattern to listen to to subscribe to basically so we're going to pass in command and then create user all right so now inside the create user method inside the arguments we can use this payload decorator which is imported from the nestjs microservice package and then we can use this to grab the payload that was sent from the API to the net server to the microservice okay and uh what I'll do is since I don't since I'm going to complet completely different project I don't have the create user dto defined in here so what I'll do is I'm going to just go ahead and copy this class right over here okay and I'm not going to actually worry about the validation at the microservice part for now you could you could handle validation here I think you should be able to um but let me go ahead and create a new folder called dto and create user. d tots and I'm just going to ignore all the validation all the class validator decorators for now just to keep things simple okay and then we're going to go ahead and import create user dto and now let's go ahead and actually console log data and I'm also just going to return data as well since we're using the request response message pattern uh or message style we're going to return something back to the API Gateway okay now before we move on the last thing that we need to do of course is register this users microservice controller in our users module so let's do that we're going to import that and then put in the controls array and then we need to go into app. module. TS and then we need to import that users module right over here okay so now that we've done that we can actually make an API call to the API Gateway endpoint so we'll make an API call to create user create user will talk to the gats server and send this command and also send the data and then the user microservice should receive the data over here so what I'm going to do is in my Docker process I'm going to go into I'm going to go right over here so let me click on nestjs microservice tutorial so this way I can see all of the logs for all of my processes and I'm going to go ahead go into Postman and I'm going to send a request to the API and notice how now so I see uh the API Gateway is logging um is logging this and let's see let's look at the users microservice as well uh let's see the user microservice doesn't seem to be logging anything so actually the reason why you're not seeing anything being logged in the users microservice and it's not being delivered is right over here in our users controller for the HTTP API Gateway project uh I actually need to use this return keyword to return this call over here I'm not entirely sure why we need to return um but you can see now by adding the return and if I look at the logs for everything if I go back to postman and send something you can see now it's being logged on both the user micros service and the API Gateway and when I don't have the return keyword okay you can see that when I click Send it only gets sent to the API Gateway so I'm not really too sure why that's the case but yeah just make sure you have this return keyword for um this Nats client. send method call so I actually just check the docs real quick just to make sure that you all are aware of this as well so the return value of the send method returns a cold observable which pretty much just means that you need to subscribe to the observable for the message to be sent so that's the reason why we were not seeing the message being logged we were not seeing the payload being logged in the users microservice app because we didn't actually subscribe to the observable and uh the reason why we can subscribe to the observable using the return keyword by returning uh the observable call is because right over here in this documentation it tells you that you can actually have Nest automatically subscribe to the observable by just simply returning it okay so then that will actually subscribe to it then that will cause the message to be sent to the user micros service so just know that you need to make sure you return this method called this.n client. send Okay so let's just go ahead and go back to postman click Send and you can see in the logs that we have these objects right over here being logged once in the API Gateway and once in the user microservice so one thing that I do also want to mention is that if I go back to the uses microservice and whatever I return here is what is actually going to show up right over here as the response so basically let's say if I want to return the actual saved user or if I just want to return anything I want let's just do something like message success this will get returned back to here so this observable and then this will return that data back to the client so you see how I can change the return value very easily so just wanted to mention that as well okay so before we move on to connecting our microservices to a database I want to show you one more way of how we can uh send messages by using the event based approach so what I'll do is I'll just set up a simple let's see so what I'll do is this I'm going to go ahead and set up the payments uh controller for the API Gateway because we're going to do it regardless anyways so I might as well just do it now so I'm going to create a new folder called payments and this will also be uh this will also have a payments module it will have a module similar to the user module like this okay and I'll just actually just copy this whole thing and paste it in here because I'm going to need them anyways uh we're going to need the Nats client module as well so that's going to be imported from the Nats client folder in the Nets client module. CS file let me remove this let me just change the name from users module to payments module now go ahead and create a controller I'll copy and P I'll copy this and let me create a new file called payments. controller. TS and remember we're in the API Gateway project right now I'm going to paste this in I'm going to remove the things that we don't need so I'll just delete all this for now and just change up uh everything that is referencing users so I'll remove users and replace this with payments and then I'll remove this users part and call this payments controller um and the we'll we'll still have the same thing for the NS client because we still need it and now what I'll do is I'll go into the payments module I will import that payments controller that I just created and pass it into the controls array right over here and then now we need to go into app. module. TS and import the payments module okay so let's just double check make sure our logs are good okay and it does say um payments controller is uh successful it mapped the payments endpoint so that's good okay so um now what I'm going to do is I'm going to go into the payments controller and still we're still in the API Gateway project and I'm going to go ahead and set up a create payment method Handler for the uh post request for payment okay so post is a decorator that we are using right over here and this is the payment create method okay I am going to set up a quick little detail for this so let's do let's create a new file called create payment. dto dots and then export class create payment dto and for the let's see for the class Fields I'm only just going to have one for now I'll just have an amount and let me go ahead and make sure that this amount is in fact a number and is not empty okay and then we'll go ahead and grab the request body for our post request for create payment so we use the body decorator create payment detail and type annotate this with the create payment detail class that we just created okay all right so now that we have let me just make sure uh yep we have validation enabled as well so we're good so now what we want to do is we want to send an event to the natat server and the net server will send that to the payments microservice not the user microservice but the payments microservice okay because remember you want your API Gateway to forward those messages to the correct microservice that's the whole purpose of this so what we're going to do is we're going to reference this.n client and instead of calling do send instead of calling the send method we're going to call Emit and then the pattern is just going to be a string so I'm going to go ahead and call this event create payment and then pass in the data which is just going to be create payment dto and that's it okay the return value of this is also an observable but remember what I said earlier uh if you don't care about the return value then you don't even have to worry about returning anything here because typically uh if you want to go with an event based approach it's ideal for just emitting the event letting the microservice do its thing and returning a response right back to the client and you don't have to wait for that event to finish processing okay so that's one thing to consider whenever you want to go with event-based approach versus the request response message style that we just did earlier okay so now we're going to go into the payments microservice project that we haven't really uh touched at all we do need to install the njs microservice package as well as the Nats package and we also need to configure everything else so it's going to be the same exact thing as the users micros service so let's just do that real quick going to go into my windows Powershell and I'll CD into payments microservice uh let me clear up my console so I'll type npmi at njs micr services and thenns okay so while that's installing I'm going to go ahead and let me just collapse this collapse the project over here and I'm going to go ahead and delete uh app controller dope. TS the app controller file and the service file because we are not going to use those and let me go ahead and go to app. module. TS remove these file Imports and remove these in these uh references in the module all right so now for the main.ts file in payments microservice it's going to look exactly the same as the main.ts file in users microservice and all of your uh microservices uh it's main. CS file will look pretty much the same so it's going to be the same exact thing right over here so I'm just going to copy this whole thing and I'm going to go ahead and just paste it so right now I'm inside the main.ts file in payments microservice project I'm just going to paste this all over here and I'll just change this to payments microservice is running and we have uh the Nats server being connected uh and we're running app. listen so we should be good to go okay perfect and now we need to do the same thing for the app. module. TS uh so we're going to set up a payments module as well because remember we need to have a microservice controller for payments microservice in order to actually subscribe to those events from the N server so I'm going to create a new folder I'm going to call it payments and I'm going to create a new file called payments. module. TS okay and then we're going to import module from nestjs common going to use the module decorator and create a class called payments module and then we need to pass in the Imports array controllers and providers okay and we also need the same uh let's see just make sure okay yep we actually should be fine I'm just trying to make sure everything is the same okay which it is okay perfect so still back in the payments module inside the payments microservice project we're going to go ahead and create a new file called payment controller. TS going to use that controller decorator that I need to import from njs common okay and then this is going to be a microservice controller so I'll call all this payments microservice controller and now let's register this controller inside the controls array in our payments module so that's going to import up there and then we're going to register the payments module in the app. module. TS by just importing that module okay so we're done with that let's just double check the logs oh yeah our app is currently down let me rerun Docker docker compose up hyphen hyphen build okay shouldn't take too long for it to start up okay so while that's starting up I'm going to explain what we're going to do inside the payments microservice controller so we're going to do the same thing that we did in the users controller in the users microservice controller back in the users microservice project so we're going to create a method inside the class that is going to handle uh whenever we receive event and in order to receive the event we're going to use a different decorator from the nestjs microservice package it's going to be called event pattern so not message pattern but event pattern okay so our application is running uh you can see now in the logs it says users uh payments microservice is running and then users microservice is running and then the API is running as well so that's perfect so everything is up and running so that's good so let's go ahead and use this event pattern controller or sorry this decorator and it gets imported from nestjs microservices package that we just installed a few minutes ago in the payments micros service package or the project and then right over here as an argument you just pass in that same exact uh string that you passed in when you called the emit method so right over here I'm in the API gway project and remember how in the regular HTTP payments controller uh I referenced the Nat's client and I called Emit and I passed in this create payment string so this is going to be the exact event that we're going to listen to just like that okay and now all we do is we just simply create a method called create payment and the rest is going to start to look very identical you can use the payload decorator to get the data so I'm going to call this create payments dto and I don't have the dto in this project in this payments micros service project so I'll go ahead and just copy it over and I'll just remove the class validators inside the payments microservice project so I'm going to create a new folder called dto or dto create a new file create payment. D.S and then just remove all of the decorators because the validation will happen in the API layer you can also do validation in the microsof as well if you want to but we're we're just going to keep things very simple for now so I'm going to go ahead and type annotate this object with this class that I just uh created inside the payments micros service project and now I can go ahead and just console log this and we should be able to uh receive this message without having to return anything back to the API or back to the Nats server so uh let's see everything should work accordingly uh let me just double check did I register the payments module I did okay so everything should work just fine let's go ahead and let's make sure the users work first so the users microservice is still working let's now make sure the payments microservice is working so I'm going to make an API call a post request to uh SL payments Okay click Send uh let's see amount should not be empty oh I forgot to provide the correct field so amount let's do 50 and notice how we get a 2011 created and if you look at the console or if you look at the logs in our Docker container you can see that uh the payments microservice is logging out the amount the object the create payment dto object and it gives us this object over here which has amount 50 so that's the data that I just sent so notice how now I don't need to send anything back because this is just how event based patterns work you can just pretty much emit an event and allow all of your microservices to subscribe to that specific event and have it perform uh whatever logic it needs to perform whenever that event is triggered and then that's it you don't have to worry about sending back a response so it's different than the first approach that we did so hopefully you can see the pros and cons between both and understand when to use which approach all right so now one more thing that I do want to do before we move on to showing you how we can connect to a database I really quickly just want to show you what I can do uh inside this payments microservice okay so what I want to do is I want to be able to communicate with the user microservice or really any other microservice in general but I want to be able to communicate with the user microservice in case if I need to notify uh the user micros service whenever something happens okay so right over here we're creating a payment and let's just pretend that we are saving it to the database for now okay once I am done with that what I want to be able to do is I want to be able to talk to another microservice so that way whenever something happens here I can notify another micros Service as well and the benefits of this is sometimes you might have um it's not as easy compared to a monolith application because in a monolith application you have everything under one single code base so it's very easy for you to communicate with uh each other because it's all under one process in microservices you have to talk to a completely different process so we have to pretty much send the data via gats via TCP connection using the Nats controller in this case send it to the other microservice and have that microservice act accordingly whenever uh it receives that event or that request in order to do that we need to make sure that we have the Nat's client injected inside the payments micros service controller so it's similar to how inside the API Gateway project right over here in our payments controller and in the users controller we injected this Nat's client over here and we also configured that in the Nats client module and then imported that into the root app module. TS okay so I'm just going to pretty much just copy this whole folder Nat's client I'm going to copy that and I'm going to go ahead and paste that into payments microservice like this uh whoops not in there inside the source folder okay okay so just make sure you have this same exact Nats client module. TS inside the payments microservice project or really any project that you will need access to the Nat's client so now what I can do is let me just first make sure that there are no errors in our project uh always got to double check to make sure okay so the payments microservice is running fine and let me just register let's see I need to go ahead import the client's uh the Nat's client module inside the payments module because I'm going to be using it inside here so Nat's client module let's just double check the logs okay we can see that uh the client's module is working just fine so now what I can do is I can set up a Constructor and inject that Nat's client so let's do inject let's import the decorator the inject decorator and the name of the Nat's client so it's going to be the same exact value that you provided for name right over here okay so Nats service natore service all in caps and then we're going to name the uh argument private uh let's see Nats client and then client um let me check what was the name of it again client proxy is the class that we're going to type annotated with client proxy and that is imported from the microservices package njs microservices package okay so we just injected it into our microservice controller or payments microservice controller uh the logs are good where there's no errors with this okay so remember make sure you have this Nets Cent module set up because if I remove it right now you'll see that uh it should throw an error let me see okay yeah is payments module valid this module so you can see that right over here uh obviously this is giving us a problem because we don't have that set up so that's good okay you can see the logs everything is working fine okay so now let's go back to the payments microservice controller in our payments microservice project and what we're going to do is I'll reference the Nat's client and then I will emit an event and I will simply say let's see uh payment created and I'm just going to pass in an empty object for now you can pass in whatever you want like I said but I'll just pass an empty object but actually you know what I'm going to pass in the dto I'll just pass in dto okay so now now this will emit the event it's going to send it to the N server the N server will push that event to all of its subscribers so all of the subscribers to the net server that are listening to this payment created event will now actually receive that event so what we'll do is we will go to the user microservice and just to keep things simple I'm not going to create a new controller for now but I just want to show you how this is going to work so inside the same users microservice controller I'm going to use the event pattern decorator and we need to make sure we match this payment created event that we're emitting so payment created and I'll just create a method called payment created and we'll just grab the payload and then for now I'm just going to leave the type as any for now and I just cuz I want to just show you what it looks like okay if I conso log data you're going to now see that uh whenever I emit this payment created event the users microservice controller in our users service project will now receive these events and it's going to log the data right over here okay so now let's go ahead and test everything out to make sure it works so what we're going to do is we're going to make a post request to our API Gateway to the payments endpoint uh this create payment method is going to be called and it's going to emit a create payment um event okay that event is going to be received on the payments microservice layer so right over here it's going to receive receive this event and then we're going to emit a payment created event payment created event and so the user microservice now will receive that events okay so it's a series of operations happening where we have all of our components all of our microservices talking to each other and that is the whole purpose of this video is to show you how microservices can be configured to talk to each other so if everything is configured correctly we should have no problem with this so let's test it out let's go ahead and click Send okay so we just clicked send and now you can see the first thing that happens is we're logging it inside the payments microservice okay so inside the payments microservice we are logging it and after it gets logged we emit this payment created method and then that payment created method is handled by the user microservice layer and then we log it there so if you look at the order of it being logged you can see that it's first logging payments it's first logging in the payments microservice and then the users microservice okay and you can see that it is being logged in both microservices because you can see the name right over here of the process or the name of the uh and the name of the running container users microservice is logging it and payments microservice is logging as well so like I said your business Logic for each one of your microservice functions can be different but this is just to show you that let's say after you created a payment you want something to happen on the users microservice layer so you would send an event to the user microservice and process that however you need to so hopefully all of that makes sense okay so the last but not least thing that we're going to do now is we're going to go ahead and connect our payments microservice and our users microservice to a shared database okay so all we need to do is just go into our Docker compost file and then uh right under underneath our net service we're going to configure a service for MySQL or MySQL okay and again you can use whatever database you want you can use postes you can use mongodb uh really anything you want I'm just going to use SQL for now cuz I personally enjoy using SQL so first I'm going to go ahead and call the service name MySQL DB and this will also be the name of the host name as well when we connect to it and then what I'm going to do is I'm going to specify the image so it's going to be the my equal Docker image that's going to uh pull from and then we're going to specify the port that we want our SQL Server to run on so because I have uh my SQL installed and running on my own local machine on my own computer and the default Port is 3306 I'm going to configure the port to be 3307 instead for Docker okay and it does I guess it doesn't really matter but I just wanted to mention that okay so now let's set up the environment variables so I'm going to configure a few and what I'll do is I'll just use the ones that I used in my live stream just to save some time uh but pretty much this allows me to set up environment variables uh so that way uh whenever it runs my SQL Server it's going to configure the root password it's going to configure the database that it's going to create uh upon startup or when it initializes it's going to uh create this test user and it's going to create this uh this the password for the test user and then it's going to run it on this port itself okay that's pretty much all these environment variables do and then the last thing that I am going to do as well is uh I think that should be it yeah I think this is all we need to do okay so now what I'll do is I'll rerun everything me run Docker let's just make sure our SQL Server can run without any issues you should see that it's going to p whole the MySQL DB image uh let's see um let's see I think that's okay yep everything is working fine the server starting I think we okay yeah seems like it's good ready for connections and if I look at docker we can see that uh our SQL Server is up and running it's right over here my SQL DB okay and I can go ahead into the shell I can click on uh exec and I can just log into the SQL server using that test user that I just created and remember that test user was created by simply just providing these environment variables right over here test user the password and if I type show databases I should see that nest jsdb database inside our SQL Server so that's good so now we need to actually connect to the database from the code so what we'll do is this I'm going to go ahead and open up a new window and let me just CD into njs microservices tutorial and uh I'm going to go ahead and CD into so let's do users microservice first okay uh let me kind of zoom in a little bit so you all can see this and I'm going to install uh type RM cuz we're going to use that as our RM to interact with our SQL database so npm install npmi at nestjs tyrm we're going to install the base type Om package and then we need to install the database driver so my SQL 2 okay again if you're using uh postr or whatever other database you're using you need to make sure you install the correct driver so we'll install that for for users microservice and then later on when we get to the payments microservice we'll install this as well but I'll do this right after I finish this okay so I just installed all of those three dependencies in my users microservice project and I'm going to just quickly install it in the payments microservice project as well just so that way we don't have to worry about it later on and then once that's done we'll configure the database connection to our SQL database I will also rebuild the docker container as well okay there we go so we just installed it in both repositories we don't need to install it in the uh Gateway API project because the Gateway API project doesn't need to connect to the database at all it's just these two projects that we have the microservices are the projects that interact with the database the the Gateway doesn't do anything with the database at all okay it passes the work down to down to the micros service and then the micros service will return data if it needs to and then the Gateway will return that back to the client okay so let me go ahead and just rebuild this Docker container whoops okay so Docker compose up build okay and once that is up and running we can can continue with setting up a database connection let's see let just make sure everything is good before we proceed okay so it seems like everything is being initialized that's good okay perfect everything is up and running okay great so now let's go into the users microservice first so inside the users microservice I'm going to go inside the app. module. TS file and I'm going to go ahead and configure type orm first so I'm going to import that type orm module from the at njs typm package so I need to go ahead and call this for root method and then I'm going to pass in an object which is the type orm module options so we're going to go ahead and start out with setting the type so this is where you need to set the correct type so since I'm using my SQL I'm going to select my SQL right over here and then now the host since again remember we're in Docker and we're running the database in a Docker container so I'm going to use that same uh host name which is the service name of uh the MySQL DB service right over here so remember how right over here this is my service name for the mySQL database so I'm going to use that as the host name which like this okay it's the same thing that we did with the NAT server when we connected to it the port is going to be 3307 um let's see what else um entities this is going to be an array we need the database name so that will be nestjs DB that is the name of our database that we configured right over here okay uh let's see what else um we're going to also use the synchronize flag set this to Tru so whenever we update our type orm entities it will immediately update the database schema so it'll update the columns the uh it will create new tables if it needs to all that kind of stuff um see am I missing anything else type hostport database oh yeah the username and password can't forget about that so username test user password test user US 1 2 3 and of course I would recommend you put all of this stuff in an environment variable so just wanted to throw it out there and now let's just look at our logs let's just make sure that the users microservice is not having any errors with connecting um and let's see now it's it is saying access denied for user and it says connection refused uh let's see it's trying it seems like it was trying to connect to Port 3306 I think I might need to restart this because it does it seems like it's not ret trying anymore yeah I think it retries 10 times to connect to the database and we just reached final time so let's restart the entire uh microservice I'm I just clicked on that that uh restart button up top okay so it seems like it was able to connect to it yep type omm core module dependencies initialize so there's no errors with it connecting to the database so that's good okay so now let's go ahead and set up our type omm entities so I'm going to create a new folder I'll call this type orm and I'll create a new folder called entities and then I'll create a new file called payment or wait what am I talking about it's user sorry user. TS and I'm going to go ahead and create a type orm entity so first we're going to create a class okay I'm ass many of you already are familiar with type RM but I will explain what I'm doing as well so in order for us to create uh well first of all type RM entities are pretty much just classes and this allows you to tell type RM that this is what our table is going to look like so type Orum we'll take this class and it'll translate it into the SQL table and it'll actually create it but we need to use this entity decorator in order for us to do that so let's just I think it is imported from sjs type RM nope sorry it's imported from type RM yep right there and then I can change the name to be users CU by default I'll just create user without the plural without the S at the end but I want it to be named users okay so now let's go ahead and set up a couple of things I'm going to go ahead and use uh this primary generated uh column decorator so this will take care of generating a unique ID for our user record whenever we create one so I'm for the ID I'm going to make this a string I'm going to make it a uu ID right over here and then we need to make sure we also match the um we need to make sure we have these fields username display name and email as well uh with display name being optional so let's start off with username so let's use the column decorator and let me just import that decorator from type RM username string and let's just make sure that we set let's see uh nullable to false uh let's see at column nullable false for email and then string and let's go ahead and do uh display name so display name is a string uh it is nullable so first let me Mark this as optional so typescript knows it is possibly undefined and then using the column decorator for this field we'll set nullable to true and uh that should be it so let's go back into where we configured type orm module so inside the app. module. TS file in users microservice and where we are uh where we have this entities array right over here I'm just going to go and import that user entity and pass it in the array like this so now uh let's see our type RM is still working just fine if there were any issues it would mention it right over here in the logs so if I were to go back into the database let me log in to the database real quick okay and let's just step into the nestjs DB database and if I do show tables you'll see that we have our users table right over here so that's perfect okay so now let's go ahead and actually uh save the record to the database now so inside the user micros service where we have this create user uh right over here uh we need to go ahead and inject the user repository but we're not going to do this inside the microservice controller uh what we're going to do is we're going to create a service class that is going to inject the users repository so that way we can actually interact with our database so I'm going to go and create a new file inside the users module in our users microservice project called users. service.ts and this will just be a class and then we're going to go ahead and just simply inject the repository inside the Constructor args we need to import this as well inject repository from and that comes from at njs typeorm like that and then we need to go ahead and pass in the entity in here so I'm going to pass in user just like that and then we need to go ahead and do private users repository and then we need to import that generic repository type which is imported from type RM some from type RM and this is a generic type so I'm going to pass in the user class over here in between the angle Brack so that way it knows that we're interacting with the user entity itself okay uh now I'm going to go ahead and and use the injectable decorator for this user service class and I need to import that decorator from at njsc common so that way we know that this is a provider we need to go into the users module. TS file and just import this users service class so that way we are registering our user service it's going to throw an error for us very likely and the reason why is because let me show you in the logs you can see that it's complaining about the users module and it's user repository dependency right over here and that's because we need to make sure we register that entity um inside the users module so it's very easy just go into the users module. TS file where you have the Imports we're going to import type orm module and uh let me just import that real quick so I'm going to import type orm module from at njs typeorm uh just fix this so type orm module and we're going to call for feature and you just pass in an array of entities so we're just going to pass in that user entity like this and now the error goes away for the user microservice okay so now we're going to go ahead and create a method called create user and this create user will take in uh the same object create user dto right over here so I'll just call this create user dto and we'll type annotate this with create user dto because we have this dto already created inside this users microservice right over here and then what I'm going to do is I'm going to go ahead and and uh declare variable and assign it the value of this do users repository do create and you can just pass in this cre create user dto okay and now we can just save the user to database so I'll do return this. user repository. saave new user like that so now let's go ahead into the controller we're going to the users micros service controller we're going to inject that users service that's pretty simple to do so private users service users service and then whenever we uh receive this message for create user we're going to go ahead and just do this return this. users service do create user and pass in the data just like that so now uh it's going to save the user to the database and it's going to return that value all the way back to the API layer okay so it's going to return this as a response and then the API Gateway will eventually have that returned back to the client right over here so let's go ahead and test this all out so what we're going to do is we're going to go ahead and make a post request to the users endpoint and we need username field so I'll do ansen we need email Anon anth dev.com and we don't need display name so let's just see what happens okay and because display name is nullable right now it's currently set to null but you can see that now I know that it was successfully saved to the database because it has that autogenerated ID right over there in the response okay and I can go into the database as well and so I'll do that real quick uh let's see let's do select asterisk select all column from the users table and you can see right over here that I have that one single user record created and I'll create another record let's do Jack and let's set a display name Jack Dev now you can see I have my second user created and if I select all of the rows and columns or so columns from users table I now see both records in the database okay so that's pretty much all we have to do with with connecting to a database uh the last thing I'll do is I'll show you how we can connect the payments microservice to our database it's going to be the exact same thing but I just want to show you how it will look like when you have a shared database across two different microservices and I'm going to show you how easy it is to actually just retrieve the data from that same database even though you're on different microservices so let's go into payments microservice and let's do this let's go into app. module. TS uh and because remember we already installed uh all of the packages for type RM and MySQL in both of the microservices project so we don't have to worry about that anymore so let me go and copy over uh the type orm module configuration from the users microservice part and I'm going to paste that in to uh the payments microservices app. module. TS file inside this Imports array right over here so just like that and of course I need to make sure I import type or a module I need to make sure I also create my entities as well so let's go ahead and create the entity for payment since we're dealing with payments in this microservice so let's do this let's create a type orm folder then we're going to do the same thing create a new folder called entities and then create a new file called payment. TS okay now one thing that I do also want to mention very quickly is since we have a lot of of the similar things that we're going to be using like for example I have the same typeor folder I have the same entities folder and then you're going to come across a point where you might need to share some of these entities because maybe your payments microservice might need the users might need to access the users uh records as well uh one thing that you could do is you can actually um create kind of like a a node module that has all of your um entities defined in one place and then publish that in like a private npm package and then install it as dependency for your project so that way can share um share all of those entities defined in one place in every single project so that way you don't have to keep creating them over and over again so uh let's go ahead and create that payment entity right now so we need to import that uh entity decorator first so let me import that from the type orm package so at entity I'm going to name this table payments and then let's create the class call it payment and then we're going to use very similar decorators that we used or the exact same decorators that we used for our user entity okay so we need primary generated column decorator as well as the column decorator and let's call that we're going to use uu IDs as well uh let's see and then let's set the ID to let's set the field name to ID and then let's just we're only going to have one field one additional field for um the column and this will just be amount which will just be a number and then let's see I think in the database I can set this to float without any issues and that should be okay now let's go back into the app. module. TS file in the payments microservice project let's go ahead and import that payment entity inside this entity array right over here uh and then let's just make sure there are no errors in the logs so no issues in the payments microservice that's good it's connecting to the database successfully and now we're going to do the same thing that we did in the users microservice where we create a payments service class and then we're going to inject that service into the payments controller and then in the payments service we're going to inject the payments repository so we can interact with the payments table so create a new file call it payments. service.ts and this is inside that payments folder and then let's just use the injectable decorator from at JS common I don't know why my typescript server is always so messed up because I always have to restart it all the time in order for the Imports to work correctly so that's why I'm doing a lot of manual Imports so I'm going to create this payments service class going to set up the Constructor and I'm going to go ahead and use the inject repository decorator and I'm going to pass that payment entity as an argument so that's going to import as well and that inject repository Decor was imported as well and then we're going to name the field name uh payments Repository repository and then type annotate this whoops to be the generic repository type and that's going to be imported from type orm and then in the angle brackets we just pass in the payment entity that way typescript knows that we're working with payments so now I'm just going to create that create payment method that is going to take in that create payment dto object and we already created that dto in this repository in this uh payment payment micros service project already so that's just going to import from the details folder and all I got to do is the same thing that I did with the user service so const new payments equals this do payments repository and then we just call the create method on the repository it's the same exact method only it's just working with payment entity I'm going to pass that dto and then we just return and then call the save method on payments repository and then we just passing this new payment object into the save method as an argument so this will actually save the payment to the database okay and then we're going to go back to the payments microservice controller and I'm going to inject that payment payments service that we just created so private oops private um payments service and then type annotate with that payment service class that I just created and let's make sure we go into the payments module and as a provider we need to add that payment Service as well okay I don't think we're quite done yet because we should have an error in the logs because we are using the payment entity or the payment repository so we need to go back into payments. module. TS and I need to import that type or module and call for feature and then pass in this array of entities and then in that array pass in the payment entity so again all the things that I just did is the same exact thing that I did for the users microservice just for payment okay it's the same exact setup okay same exact setup everything is the same okay and the error goes away now regarding that payment repository so now we should be able to create payments oh wait I forgot one more thing I need to go ahead and actually call this payments service um and call the create payment method so what I'll do is I'll do const new payment equals uh so since this payments service create payment method is it returns a promise so it's asynchronous we're going to use async AE so let me add the async keyword in front of the create payment method and let me await the method call so this. payment service. create payment and just pass in that dto okay so and what I'll do is instead of passing the dto I'm going to pass in the new payment that we just created okay and this remember this is going to be sent to the net server and all of its subscribers that are subscribing to this event will receive this event with the new payment that was created okay so again this allows you to create distributed um asynchronous microservices that don't depend that don't necessarily need to depend on each other all in one single monolith application okay so let's go ahead and test everything out so um let's see let's go ahead and create a payment right now and we only need the amount field let's do 500 click Send let's see oh it's it's payments sorry click send notice how we get a 21 created no response was returned back that's fine because we're using the event-based approach so we have to worry about that but you can see now uh because in the users microservice I was subscribing to that create uh payment created event I can see that it is being logged and if I go into my database right now if I show all the tables you can see that the payments table is created right there and I can go ahead and grab all of the records for payments so you can see we have the ID and the amount so that has how we can create payments in the create in in the payments microservice and have it completely uh isolated from the users microservice so hopefully all of that makes sense now there's one more thing that I do want to do before I end this video I want to show you how we can actually uh reference our data in a relational format because right now we are using SQL a relational database and typically with relational databases you'll have data that is relational okay and you'll have have these uh responses that you get from querying the database that will have like a bunch of tables joined together so in an actual realistic application you'll have your user entity your user table having a on to many relationship with the payment table right because a user can have many payments and a payment belongs to one single user itself assuming that that's how we're going to structure it because in some cases you might have a payment belonging to two different users assuming that that you have two users making a payment on one single transaction something like that but we're going to keep it simple so I want this user to have a on to many relationship with the payment eny as well so what I'm going to do is I'm going to go ahead and first update this payment um entity so we're going to need to set this up so that we can actually have type orm recognize that this is a one to many and many to one relationship so in order for this to happen I need to make sure I have all of the entities in both the M the payments microservice project and the users microservice project as well so what we're going to do is we're going to go ahead and take this user entity that we created uh inside the users microservice project and I'm just going to go ahead and create that inside the payments microservice is going to be the exact same thing okay and then we're going to do this what we're doing in the payments microservice now we're going to do the same same thing in the users microservice after but we need to define the one to many and many toone relationship between user and payment okay so user uh is going to have many payments so that's a on to many relationship and payments is going to have a many to one relationship okay because many payments can belong to one user and a user can have many payments so let's go ahead and inside our user class inside this entity we're going to use the one to many decorator and that's going to be imported from type omm package and then we need to specify the target relationship so the type of this is going to be payment so we need to import that payment entity that is already created from before and then we need to pass in the inverse side right over here so this is going to be a callback function and the object here is the payment itself and then we need to actually Define this field in the payment class we'll do that in just a bit but the field is going to be this user field and currently it gives us an error because it's not it doesn't exist but we're going to create that in the payment entity in just a bit but the field over here is going to be payments and the type is going to be an array of payments because remember a one to many relationship in typescript it's going to look like an array of all of the payments for this user that relates to this user so now we have to go to the payment entity and we need to define the many to one relationship so we need to use the many to1 decorator which is also imported from type orm package and then very similar to what we just did with the one too many we're going to go ahead and pass in the Target as the user so we need to import the user entity and this user entity remember is what we just created in this payments microservice project and then the call back function as a second argument over here we're going to have this user object and we just simply reference user do payments like this okay and then for the field it's just going to Simply Be user and then the type is going to be user okay so hopefully this makes sense and one more thing that I will do is I'm going to use this join column decorator so that way I can join uh this very easily you can see that it says it can also be used on both one to one and many to one relationships so that way when we actually retrieve uh the user we can also grab uh payment data as well all in one go okay so hopefully this um hopefully this makes sense okay now let's go into the app. module. TS and we need to also uh whoops not here oh yeah right over here uh we need to also register the user entity as well so let me do that and then let's just also make sure we are registering it uh let's see um I might need to use it inside the payment module as well so I will import this over here okay all right let's go ahead and make sure our console let's see all right I'm not sure what was going on with that but I had to manually restart the container so now everything is good uh and our user entity is being registered accordingly so that's good um okay so let's just make sure we do the same thing for the users microservice so uh I'm going to go ahead and grab that payment entity and create this right over here payment. TS pastes right over here and we need to oh whoops let me move this inside the payments or the entities folder right here okay so they're in the same entities folder and uh let's go back into the user entity and uh add that one to many decorator in the field so like this so now we're inside the users microservice project and we just uh added this one too many reference for the payments and we also create the same exact payment entity in this project as well so now both projects have both enti these and they're both consistent let me just fix this up and import these decorators okay let me also import the payment entity as well okay so now that is all fixed let's just register the payment entity as well and I'll additionally register that in the users module inside this for feature array okay um so again doing the same exact thing for both repositories just for the different entity okay so let's just double check our logs everything is working fine all right so now uh what I can do is this so whenever I create a payment we need to make sure that we know who that payment is associated with now since we actually don't have any um authentication we don't have any session data to be able to figure out who the user is there's no state in our application with our uh HTTP requests uh just for now what I'm going to do is I'm going to make it a requirement on the dto so right over here in the create payment dto I'm going to make it a requirement to specify the ID of the user that we want to create this payment for because normally like I said if you if you have authentication you can just very easily figure out who that um who that payment is going to be for so you don't need to have it required in the field in the uh request body so I'll just do is not empty and then ID which is going to be a string because remember we're using uyu IDs uh and I'll just leave it like this for now okay so what's going to happen is we're going to um we're going to go ahead and make a post request to this create payment uh endpoint and then we're going to go head and Emmit the event to the natat server the natat server will send that event all the way to the payments microservice okay our payments microservice controller we are subscribing to that create payment event and currently we're only uh creating the payment now I am creating the payment in the database but I'm not saving the user that it is related to um so first let me make sure uh my create payment dto is consistent across both the Gateway project as well as the payments microservice project so you can see that the payments microservice project has this create payment dto that's the same one but it's missing this ID field let me change this to user ID instead and I want to make sure this is also on the create payment dto as well for the payments microservice okay and now we need to go back to the payments microservice project right here and so I'm inside the payment service and what we need to do is we actually need to grab the user from the database now here's the thing though because we are using a shared database we can easily just inject this user repository in our code and grab the user now there are situations where you might not be having a shared database and you might have each microservice connected to its own database or its own database table and so you can't just easily grab all the data from one single database you have to talk to the other microservice and grab the data from that microservice and also I would also encourage you to not you know inject repositories that are not necessarily related with the payment domain itself so for example um if we were to inject the user service or the user repository inside this payment service class that would be the easiest thing to do to use that to grab the user from the database by its ID but it starts to kind of add more things that are not relevant to the payments micros service itself because now you're also grabbing you're also using the user repository to interact with the user table so what I'm going to do instead is I'm going to grab that user record from the users's microservice as well and we can very easily do this by instead of not instead of using the event-based approach we can use the request response approach so that way we can at least wait for that response to come back from the user microservice before we proceed with anything else so first I need the user ID so I'm going to go ahead and do this I'm going to destructure the user ID from the create payment dto and I'm also going to grab the amount as well but uh since the create P DT might also have more Fields you know later on I'm just going to destructure the rest into this create payment I'm going to pack all of the fields back into this object over here okay and I do need to go to the users microservice and what I need to do is I need to let's see right over here in the users microservice controller I'm going to use the message pattern decorator and I'm going to whoops I'm going to use uh a command called get user by ID and then get user by ID and then we need to pass in the ID to the user microservice for this specific pattern for get user by ID so the payload is going to be I guess an it's still going to be an object that is going to have the user ID I'm not just to save some time because we're kind of running out of time I'm not going to do any type annotation for this okay so what I'll do is uh I'm going to go ahead and grab the user ID from data like this and I'm going to go ahead and go into the user service class and I'm going to create a method called get user by ID and we're going to pass in the user ID which is a string and then all I'm going to do is return this. user repository find one uh let's see and then I can pass in an option so I can actually I'm going to do find one by instead whoops I'm going to use find one by instead so that way I can specify I'm trying to find it by the user ID like this okay and of course this will return the user um let me see finds the first entity it seems like this returns yeah it returns one single user so that's good okay perfect all right so now let's go back into the user microservice controller in our users microservice project and we're going to use async and ao8 to grab the user from the database so const find user equals 08 this. user service uh get user by ID pass in the user ID like this and uh let's see what I'll do is I'll just return return um H let me do this I'm just going to return this whole call actually so return user service. getet user by ID so we don't really care if this is null or or not because we'll let the um payment micros payment micros service handle that okay so this will return whatever the return value is from the database and we'll get that inside the payments microservice right over here so I'm back inside the payments service inside our payments micros service project so I'm going to go ahead and do this I need to grab this gats service this Nats client in order for me to actually um send a message all the way to the user microservice so we're going to inject that right over here u whoops and then let me import the client proxy as well okay and so what I'm going to do is I'm going to go ahead and create a variable called user and then um here's what we're going to do we're going to reference Nat's client and then we're going to go ahead and call do send and the command pattern is going to be get user by ID so we need to make sure that matches and then we need to pass in the user ID that we want to grab from the database now here's the though this is an observable or the uh the do send method returns an observable so we can't easily just grab it we can't easily just grab the return value by just assigning it to a variable because it's an observable we need to subscribe to it now before there was a method called two promise that can pretty much just grab you the return value from that observable but since it's deprecated they recommend you use this rxjs operator called last value from so I can just import last value from from rxjs which is actually already installed by default when you scaffold your nestjs project so I'm going to go ahead and just use this last value from operator and it's just a it's just a function so I'm just going to call last value from pass this over here and you can also type annotate this as well because it's generic so I can type annotated with user so that way now it knows that this is a user or a promise user and we need to await this method call so let me add the acing keyword in front here and then this is how we can actually grab the user so we should be able to just grab the user before we do any uh thing with creating the payment so let me just kind of console log this a few times uh let me do new payment let me consant log new payment as well just make sure everything is happening in sequential order so um now uh what's going on over here did I accidentally copy oh I accident I accident whoops sorry about this I accidentally copied uh I accidentally injected the payment service let me remove that and you also remove that as well okay so there are no errors currently that's good so what we're going to do is we're going to go ahead and create a payment by making an API call to payments we need to make sure we send the user ID as well so now I need to actually grab a user ID from the database so let me just go back to the SQL database shell and I'll use ansen I'll use that ID okay so hopefully this will work fine if I click Send okay keep in mind we aren't attaching the payment to the user just yet I just want to make sure the logs are logging in correct order so you can see right over here uh the payment microservice is logging the user so it was able to find the user successfully we were able to log that user user and then it created the payment and then it saved it to the database right over here and then right over here you see that it's being logged in the user microservice because remember in the users microservice we are subscribing to that payment created event okay so everything is working in sequential order so that's good let me try ahead and create a couple more just to make sure um everything is still good okay perfect and you can see still in the database if I go ahead and grab all payment records there's still no reference to the user ID just yet because we haven't attached it so this is the next thing that we have to do is when we create this user or when we create this payment we're going to go ahead and pass in all of the fields and all the field values from create payment dto by using the spreader operator and then we're also going to add this user reference over here so this is going to be the user that we just found but we also need to make sure we check if user is defined cuz if user is not defined this is not going to work so so what we'll do is this if user is defined we will do all of this if user is not defined um let's see if user is not defined then we can just simply return N I guess and then inside the payments microservice controller um we can just emit the event only if new payment was uh only if new payment is find so uh if new payment then we'll liit the event so if if uh if the user was not found then it won't do anything okay so let's just try this out let's make sure it works so let's go over here let's create a payment now let's look at the logs okay and now you can see that uh when I when I log this object over here you can see that the user is actually attached to that payment record now and it's being logged in the payment microservice as well as the user microservice cuz we're receiving that uh event okay if I were to actually just change the ID to something else that doesn't exist in the database you're going to see now uh we have null okay and the user's microservice doesn't log anything because it didn't receive that event because uh we cannot find the user in the database so nothing actually happened at all just wanted to show you all how to handle that case as well now let's go ahead and query the database and you can see now when I select all the records from the payments table I now have this user ID being referenced to payments okay and now here's the thing so we want to also be able to retrieve users from the database and all of its payment records as well so what we need to do is we need to set up um an endpoint to actually grab all the users so I'll do that finally and then we can end the video cuz I know it's pretty long but I really just wanted to show this case so that way all of you can understand how this all comes into play so we're going to go back to our API Gateway project and we're going to set up a get request okay and we're going to do get user um by ID and I'm going to go ahead and use a route parameter for the user ID and I'm going to use the pram decorator to grab that route ID that route parameter and that's going to be a string so now whenever I visit SL user slid and pass in the user ID over there it will go ahead and call this endpoint and so what we're going to do now is um since we need to talk to the natat server to talk to the user's microservice to grab the user buy its ID we're going to use request and response approach because we want to make sure we're returning a response back to the client so I'm going to do return this.n client. send command get user by ID and we actually already created this um already earlier in the users microservice if you look at the uh controller right over here we already have this um get user by already created that was used by the payments microservice okay so we don't even need to do anything else but just send this call to the the users micros service so uh user ID will just be the ID and uh yeah that's pretty much it so let's try this out so now let me go ahead and grab this user ID I'm going to go ahead and make a users uh SL ID API call and now I can see I can actually get that user from the database but I don't get the actual payments as well in order to get the payments we need to make sure that we are also um uh grabbing the relations any relations that we need and that's actually pretty simple so what I'm going to do is right over here where I have find one by there's actually a second argument that you can pass or not second let me see so actually we need to not use find one by but we need to use find one and then we can go ahead and uses where which is pretty much it's it's very equivalent to using find one by because in the we object you will just set the ID to user ID like this and then outside of this object you're going to specify the relations and this is just going to be an array of the relations that you want to grab so in our case we want the payments relation because that's the name of the field that is defined on the user entity that we have right over here so we're going to specify the relations for payments so now this should grab us all the payments now and you can see that it's right over there so that is how that works when it comes to grabbing the user and all of its payments okay and because it's all connected to one single shared database it can very easily just perform one query and grab all of the relational data that it needs so hopefully that makes sense and of course if I were to pass an invalid ID it should just return nothing but again ideally what you would want to do is you would want to get the return value from the microservice so in our case when we call uh the get user by ID from the user microservice uh this will just return whatever is returned from the user service method which is right over here so this will return the user or a null value so we pretty much want to subscribe to this observable and grab that value that was returned and remember how earlier I said that we need to use the last value from rxjs operator to do that so I'm just going to do that very quickly so const uh user equals awaits last value from that's going to be imported from rxjs pass in um this Nats client. send method call and let's just add the asyn keyword in front of the get user by ID method and so what we can do from the API from the http API layer is we can say if there is a user we will just return a user like this um otherwise we'll go ahead and throw a new HTTP exception and we'll just say user not found and the status code will be 404 so now watch this if I click Send we actually get a 44 not found error but if I were to pass in the correct uh user ID let me see did I put the did I put the right one there we go okay yeah so that's the right one right over here and we actually get the user back okay so now you can start to see that we have a microservice architecture we have one API that forwards the message to the correct microservice we let the microservice do all of the database reads and writes um it'll send the message back to the N server the N server will send that back to the API Gateway and the API gate will just send it back to the client okay so instead of having your API server doing everything you pass off that load to the corresponding micros service so I very much hope that this whole video was informative to you all I had a lot of fun making this video um all of the code that I wrote in the description everything that you see over here the docker compos file all the docker files everything will all be in a GitHub repository and I'll leave a link in the description so that you all can use it as a reference I want you all to be able to understand how this works so if you have any additional questions feel free to join the Discord server that is linked in the in the description ask your questions in the comments down below I check my comments every single day so I'm more than happy to try my best to answer any questions because I understand that this topic can be um you know a little bit more um abstract to understand but hopefully that this video showed you how all this stuff works and maybe you can even build something on your own because like I said there's countless amounts of approaches on how you can set up microservices so I would very much love to hear uh what you came up with so thank you so much for watching this video I hope you all enjoyed it and I will see you all in my next video peace out
Info
Channel: Anson the Developer
Views: 9,768
Rating: undefined out of 5
Keywords: nest.js, nestjs, microservices, docker, nats
Id: 5HlsgPRcm3w
Channel Id: undefined
Length: 140min 27sec (8427 seconds)
Published: Fri Dec 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.