Okay.
So ready to generate our final microservice, which will be our notification service which we'll use
to notify the users after we have successfully charged their card and created their reservation.
So let's go ahead and in the terminal we'll go ahead and use the CLI to generate a new app and we'll
go ahead and call this application notifications.
So I've gone ahead and created our new app here.
So we'll start off by creating a new Docker file as we've done before in the root of the Notification
Service.
And I'll go ahead and copy over the Docker file from the payment service and paste this in here, just
swapping out the last line where we go into the notifications folder to start this service up.
So after we've added our Docker file, we can go into our Docker compose and we will go ahead and copy
the payments setup here and paste it once again.
And we're going to swap this out for the notifications service.
So we'll keep everything the same, except we'll change the path to the Docker file here.
And of course we'll make sure we start the notification service with the command here.
And for our M file we will also look for the notifications.
M Now we don't need to expose any ports here and we also don't need to expose ports on the payment service
either because this is only exposed over TCP.
So I'll get rid of this section here, but I will go ahead and create a dot env in the notifications
root directory as well here so that we can actually provide environment variables to this service.
But this should be everything we need to actually start up our notification service.
So let's go back in our terminal and run a docker, compose up here.
So you can see here that our notification service has started up successfully here.
So we can go back to the notifications main.ts and start fleshing this out.
I'll go ahead and copy over the main.ts from our payments bootstrap here because it'll largely be very
similar.
We'll paste this in here and we'll go ahead and swap out the payments module here.
Now for the notifications module to pass into the nest factory, we'll go ahead and import the config
service from nest config as well as the transport from Nestjs microservices.
So we're still going to listen on all IP addresses for this microservice and get the port from the dot
m file here.
So if we look at the dot m for the payment service, we know we're listening on Port 3003.
So let's go ahead and listen on Port 3004 here.
And lastly, make sure we import the logger here from Nestjs Pino so we can hook into the logger module.
Next, let's go to our notifications module and we'll go to the payments module here and just copy over
the existing imports as well.
So if we go to the notifications module, we'll go ahead and add these imports.
So import the config module from nestjs config and we'll import star as joy from joy and then go ahead
and import the logger module as well.
So in the terminal we'll have to go ahead and restart our containers to read in the new dot m file for
our notification service.
So you can see here we're complaining about the stripe and the notification service.
So let's go ahead and make sure we remove the stripe secret key as of course we don't need this in the
notification service.
So after we remove this, we should see the notification service starting up.
And you can see we now have an error about the logger module.
And the problem is we're importing logger module from Pino.
Make sure we import the logger module from app slash common here instead.
So finally we can see the notification service saying the nest microservice has successfully started.
Okay, so next I'll go ahead and in our notifications controller I'll delete our default route here
and I'll delete this default function in the notification service.
We want to expose a new event pattern for this microservice.
So an event pattern is the event based microservice communication approach where we actually won't be
sending a response back from this notification service.
Instead, we will simply receive an event from a different service and do something with that without
having to reply back.
So this is ideal because we don't have to maintain overhead by requiring a request response channel.
It takes less time and it's more of a simpler approach because we're just notifying users.
We don't really need to respond back to the calling application in this approach.
So we'll go ahead and define a new event pattern decorator here from Nestjs Microservices.
So I'm going to go ahead and call this notify email because we are going to be emailing the user.
So I'll have an async function here with the same name, notify email, and we are of course going to
extract the payload so we can still send a payload.
So we'll go ahead and define the type.
Here.
I'll create a new folder as we've done before, and I'll create a notify email updates and I'll export
this notify email, DTO, which is just going to have an email of type string here and we can actually
apply the same validation as we've done before and specify that this should be an email from class validator
in the notifications controller.
We'll now say that this is a type notify email, DTO and then we'll call this DOT notification service
dot, notify email and pass the data down into it.
So to apply validation, of course we'll go ahead and apply the use pipes operator and call new validation
pipe here.
So in the Notification Service, let's go ahead and create a new async notify email method here that
takes in the email which will be of type notify email, DTO And for now, let's just go ahead and console.log
the email here so we can see that we are receiving it.
So what we're actually going to do, the notification is in the payments service directly.
So in the payment service, after we create a charge of any type, we are going to email the respective
user that we're creating the charge for.
So you could imagine that there could be multiple services utilizing this payment service, not just
the reservation service, no matter what.
We always want to notify the user.
So we'll keep this event emitting in this service.
Likewise, there could be multiple notification channels we want to use eventually beyond just email.
So this is good because we now have a service dedicated just for notifying.
And of course we can scale these services independently of one another.
So back in the payments module now we're going to go ahead and call clients module dot register async
here where we can provide all of our different clients.
In this case, we're only going to have the payment service set up.
So I'll go ahead and have a new object here where we specify the name and I want to add the notification
service, of course.
So I'll follow our similar pattern of adding our service to our Libs slash common services file here
so that way we can use this in other services as well.
If we need to communicate to this service, I'll export a const called notifications service and I'll
call this notifications here.
So I'll go ahead and now import the notification service from app slash Common and we can have a use
factory here to actually inject the config service as we've done before.
So this will be of type config service from nestjs config.
And now we can go ahead and return an object that has.
And so now inside of this use factory we'll go ahead and specify the transport here.
Of course we know this is transport dot TCP and then we'll have the options object where we'll specify
the host.
In this case, we'll pull it off the config service and provide the environment variable, which I'll
go ahead and call notifications.
Host And then for the port we'll do the same thing here.
I'll pull it off the config service dot, get port now and I'll go ahead and also add this to our joy
validation here.
So I'll have a new notifications host environment variable that will be a string and that's required.
And I'll also copy this for the notifications port and this will be a number that is also required.
So we need to go ahead and update our dot env now to actually have the notifications information here.
So I'll add the notifications host first, which as of course we know from the Docker compose will be
the name we've specified, which in here is just notifications.
So we can go ahead and copy this directly and just paste this in.
And then also the notifications port we know is on 3004.
This is what we specified in our EMF here and where we are listening on our microservice here in our
bootstrap function.
So of course we'll have to restart our containers to pick up these latest environment variables.
And finally in the payments module, don't forget we also need to add an inject property here where
we go ahead and actually inject the config service.
So the payment service has started back off successfully, which means we have all of the environment
variables we need.
And this also means now we can go into payment service and actually use the inject decorator here,
notification service.
And remember, we're importing this from app slash common.
So let's go ahead and update our imports here and we'll also add the.
Rate charge data from apps common.
So we'll go ahead and call this the notification service which will be of type client proxy from nestjs
microservices and of course make sure that this is also private read only so we can use it in the class
here.
So like I said, right after we create this payment intent and we actually successfully charge the user,
that's when we want to actually emit the event to the notification service.
And like I said, we don't need to wait for a response from the Notification Service.
We'll just send this off and let it handle it.
So to do this we can call this DOT notification service dot Emit, and we know we need to specify the
pattern here.
If you remember, the pattern here was notify email.
So let's go ahead and add, notify email, and then we have the data where we can specify the email
here.
Now, right now we actually aren't even providing an email to the payment service.
Let's go ahead and change this.
Okay.
So in order to receive the email in the payment service, we know we're sending the Create charge request
from the reservation service when we actually create a new reservation and we already have access to
the user in our reservations controller thanks to our JWT auth guard and our current user decorator.
So let's refactor this a bit by instead of taking in the user ID here, let's go ahead and get the entire
user directly and we can destructure the properties we know we want off of it, which will be the email
and the ID and this will come off of the user DTO from app slash common and make sure we have an underscore
ID here as well.
And I'll also go ahead and rename this variable to user ID.
So we're still providing the user ID in the reservations repository.
However, now instead of just passing in the Create Reservation, DTO dot charge, which we know is
the card in the amount, we will also include the user's email.
So let's go ahead and create a new object here.
We'll spread the Create Reservation DTO charge and then add the email property here.
Now go back to the reservations controller and instead of passing in the underscore ID, we'll pass
in the whole user object.
So now in the payments controller, we want to update the DTO for Create charge method to include the
email.
However, right now we're using the shared Create charge DTO from our app slash common folder and we
don't want to add the email to this base.
Create charge DTO Instead we can create a new DTO that's specific to the payment service and extend
this create charge DTO to get the card and amount properties with the validation and add our own email
property on top of it.
So let's go ahead and do this in the payment service.
I'll go ahead and create a new DTO in the DTO folder called Payments Create Charge dot DTO, and this
will be a class called payments Create Charge DTO and importantly, this is going to extend the create
charge DTO from app slash common.
So again, we're going to inherit the existing properties, the card and the amount, and now we can
add the email field of type string and specify that this should be an email here from class validator.
Now in the payments controller here, instead of using the Create charge DTO, we will use the payments,
create charge, DTO we can delete the unused import.
And now when we pass our data to the create charge method and make sure we import the payments, create
charge DTO instead where we know we have the card amount as well as the email, and now we can properly
emit the notify email event here to the specified email.
We'll make sure all of our containers are started up.
And now if we firstly log in to get a JWT cookie and create a new reservation, we wait for the reservation
to get created and in the logs we should now see the notification service correctly console logging
out our email so we can see that we're sending off the email correctly from the reservation service.