WEBVTT

00:00.020 --> 00:00.290
Okay.

00:00.290 --> 00:05.480
So ready to generate our final microservice, which will be our notification service which we'll use

00:05.480 --> 00:11.000
to notify the users after we have successfully charged their card and created their reservation.

00:11.000 --> 00:18.290
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

00:18.290 --> 00:22.460
go ahead and call this application notifications.

00:22.610 --> 00:25.550
So I've gone ahead and created our new app here.

00:25.550 --> 00:32.480
So we'll start off by creating a new Docker file as we've done before in the root of the Notification

00:32.480 --> 00:33.230
Service.

00:33.230 --> 00:39.200
And I'll go ahead and copy over the Docker file from the payment service and paste this in here, just

00:39.200 --> 00:45.920
swapping out the last line where we go into the notifications folder to start this service up.

00:46.250 --> 00:53.270
So after we've added our Docker file, we can go into our Docker compose and we will go ahead and copy

00:53.270 --> 00:57.200
the payments setup here and paste it once again.

00:57.200 --> 01:02.010
And we're going to swap this out for the notifications service.

01:02.010 --> 01:07.110
So we'll keep everything the same, except we'll change the path to the Docker file here.

01:07.290 --> 01:11.940
And of course we'll make sure we start the notification service with the command here.

01:11.940 --> 01:15.960
And for our M file we will also look for the notifications.

01:15.990 --> 01:23.160
M Now we don't need to expose any ports here and we also don't need to expose ports on the payment service

01:23.160 --> 01:26.310
either because this is only exposed over TCP.

01:26.310 --> 01:32.610
So I'll get rid of this section here, but I will go ahead and create a dot env in the notifications

01:32.850 --> 01:38.970
root directory as well here so that we can actually provide environment variables to this service.

01:38.970 --> 01:42.840
But this should be everything we need to actually start up our notification service.

01:42.840 --> 01:47.370
So let's go back in our terminal and run a docker, compose up here.

01:47.370 --> 01:51.840
So you can see here that our notification service has started up successfully here.

01:51.900 --> 01:57.080
So we can go back to the notifications main.ts and start fleshing this out.

01:57.090 --> 02:04.110
I'll go ahead and copy over the main.ts from our payments bootstrap here because it'll largely be very

02:04.110 --> 02:05.010
similar.

02:05.100 --> 02:09.810
We'll paste this in here and we'll go ahead and swap out the payments module here.

02:09.810 --> 02:15.870
Now for the notifications module to pass into the nest factory, we'll go ahead and import the config

02:15.870 --> 02:21.510
service from nest config as well as the transport from Nestjs microservices.

02:21.510 --> 02:26.690
So we're still going to listen on all IP addresses for this microservice and get the port from the dot

02:26.730 --> 02:27.870
m file here.

02:27.870 --> 02:33.480
So if we look at the dot m for the payment service, we know we're listening on Port 3003.

02:33.480 --> 02:37.470
So let's go ahead and listen on Port 3004 here.

02:37.470 --> 02:43.590
And lastly, make sure we import the logger here from Nestjs Pino so we can hook into the logger module.

02:43.590 --> 02:50.340
Next, let's go to our notifications module and we'll go to the payments module here and just copy over

02:50.340 --> 02:52.380
the existing imports as well.

02:52.590 --> 02:57.630
So if we go to the notifications module, we'll go ahead and add these imports.

02:57.630 --> 03:06.270
So import the config module from nestjs config and we'll import star as joy from joy and then go ahead

03:06.270 --> 03:09.000
and import the logger module as well.

03:09.000 --> 03:15.570
So in the terminal we'll have to go ahead and restart our containers to read in the new dot m file for

03:15.570 --> 03:17.130
our notification service.

03:17.130 --> 03:20.910
So you can see here we're complaining about the stripe and the notification service.

03:20.910 --> 03:25.620
So let's go ahead and make sure we remove the stripe secret key as of course we don't need this in the

03:25.620 --> 03:27.300
notification service.

03:27.300 --> 03:31.620
So after we remove this, we should see the notification service starting up.

03:31.620 --> 03:34.920
And you can see we now have an error about the logger module.

03:34.920 --> 03:39.000
And the problem is we're importing logger module from Pino.

03:39.030 --> 03:45.540
Make sure we import the logger module from app slash common here instead.

03:45.540 --> 03:51.300
So finally we can see the notification service saying the nest microservice has successfully started.

03:51.300 --> 03:57.660
Okay, so next I'll go ahead and in our notifications controller I'll delete our default route here

03:57.660 --> 04:01.440
and I'll delete this default function in the notification service.

04:01.440 --> 04:05.010
We want to expose a new event pattern for this microservice.

04:05.010 --> 04:12.030
So an event pattern is the event based microservice communication approach where we actually won't be

04:12.030 --> 04:15.630
sending a response back from this notification service.

04:15.630 --> 04:21.120
Instead, we will simply receive an event from a different service and do something with that without

04:21.120 --> 04:22.530
having to reply back.

04:22.530 --> 04:28.200
So this is ideal because we don't have to maintain overhead by requiring a request response channel.

04:28.200 --> 04:33.390
It takes less time and it's more of a simpler approach because we're just notifying users.

04:33.390 --> 04:37.560
We don't really need to respond back to the calling application in this approach.

04:37.560 --> 04:43.620
So we'll go ahead and define a new event pattern decorator here from Nestjs Microservices.

04:43.620 --> 04:49.440
So I'm going to go ahead and call this notify email because we are going to be emailing the user.

04:49.440 --> 04:55.920
So I'll have an async function here with the same name, notify email, and we are of course going to

04:55.920 --> 04:58.680
extract the payload so we can still send a payload.

04:58.680 --> 04:59.970
So we'll go ahead and define the type.

04:59.990 --> 05:00.500
Here.

05:00.500 --> 05:10.280
I'll create a new folder as we've done before, and I'll create a notify email updates and I'll export

05:10.280 --> 05:17.150
this notify email, DTO, which is just going to have an email of type string here and we can actually

05:17.150 --> 05:23.840
apply the same validation as we've done before and specify that this should be an email from class validator

05:23.950 --> 05:25.760
in the notifications controller.

05:25.760 --> 05:33.440
We'll now say that this is a type notify email, DTO and then we'll call this DOT notification service

05:33.440 --> 05:37.730
dot, notify email and pass the data down into it.

05:37.730 --> 05:46.400
So to apply validation, of course we'll go ahead and apply the use pipes operator and call new validation

05:46.400 --> 05:47.270
pipe here.

05:47.270 --> 05:54.620
So in the Notification Service, let's go ahead and create a new async notify email method here that

05:54.620 --> 06:04.140
takes in the email which will be of type notify email, DTO And for now, let's just go ahead and console.log

06:04.140 --> 06:06.840
the email here so we can see that we are receiving it.

06:06.840 --> 06:12.420
So what we're actually going to do, the notification is in the payments service directly.

06:12.420 --> 06:20.010
So in the payment service, after we create a charge of any type, we are going to email the respective

06:20.010 --> 06:22.080
user that we're creating the charge for.

06:22.080 --> 06:27.780
So you could imagine that there could be multiple services utilizing this payment service, not just

06:27.780 --> 06:30.120
the reservation service, no matter what.

06:30.120 --> 06:31.830
We always want to notify the user.

06:31.830 --> 06:34.860
So we'll keep this event emitting in this service.

06:34.860 --> 06:40.740
Likewise, there could be multiple notification channels we want to use eventually beyond just email.

06:40.740 --> 06:45.150
So this is good because we now have a service dedicated just for notifying.

06:45.150 --> 06:48.870
And of course we can scale these services independently of one another.

06:48.870 --> 06:55.740
So back in the payments module now we're going to go ahead and call clients module dot register async

06:55.740 --> 06:59.070
here where we can provide all of our different clients.

06:59.070 --> 07:01.920
In this case, we're only going to have the payment service set up.

07:01.920 --> 07:07.590
So I'll go ahead and have a new object here where we specify the name and I want to add the notification

07:07.590 --> 07:08.430
service, of course.

07:08.430 --> 07:19.650
So I'll follow our similar pattern of adding our service to our Libs slash common services file here

07:19.650 --> 07:22.500
so that way we can use this in other services as well.

07:22.500 --> 07:29.640
If we need to communicate to this service, I'll export a const called notifications service and I'll

07:29.640 --> 07:31.470
call this notifications here.

07:31.470 --> 07:40.020
So I'll go ahead and now import the notification service from app slash Common and we can have a use

07:40.020 --> 07:45.330
factory here to actually inject the config service as we've done before.

07:45.330 --> 07:49.920
So this will be of type config service from nestjs config.

07:49.920 --> 07:53.850
And now we can go ahead and return an object that has.

07:53.880 --> 07:58.830
And so now inside of this use factory we'll go ahead and specify the transport here.

07:58.860 --> 08:04.430
Of course we know this is transport dot TCP and then we'll have the options object where we'll specify

08:04.430 --> 08:05.270
the host.

08:05.270 --> 08:10.670
In this case, we'll pull it off the config service and provide the environment variable, which I'll

08:10.670 --> 08:13.070
go ahead and call notifications.

08:13.100 --> 08:17.570
Host And then for the port we'll do the same thing here.

08:17.660 --> 08:25.180
I'll pull it off the config service dot, get port now and I'll go ahead and also add this to our joy

08:25.190 --> 08:26.480
validation here.

08:26.480 --> 08:34.820
So I'll have a new notifications host environment variable that will be a string and that's required.

08:34.820 --> 08:43.820
And I'll also copy this for the notifications port and this will be a number that is also required.

08:43.820 --> 08:51.650
So we need to go ahead and update our dot env now to actually have the notifications information here.

08:51.650 --> 08:59.330
So I'll add the notifications host first, which as of course we know from the Docker compose will be

08:59.330 --> 09:03.240
the name we've specified, which in here is just notifications.

09:03.240 --> 09:07.590
So we can go ahead and copy this directly and just paste this in.

09:07.590 --> 09:12.930
And then also the notifications port we know is on 3004.

09:12.960 --> 09:20.730
This is what we specified in our EMF here and where we are listening on our microservice here in our

09:20.730 --> 09:21.900
bootstrap function.

09:21.900 --> 09:27.780
So of course we'll have to restart our containers to pick up these latest environment variables.

09:27.780 --> 09:34.320
And finally in the payments module, don't forget we also need to add an inject property here where

09:34.320 --> 09:37.440
we go ahead and actually inject the config service.

09:37.440 --> 09:42.630
So the payment service has started back off successfully, which means we have all of the environment

09:42.630 --> 09:43.770
variables we need.

09:43.770 --> 09:50.040
And this also means now we can go into payment service and actually use the inject decorator here,

09:50.070 --> 09:51.900
notification service.

09:51.900 --> 09:56.370
And remember, we're importing this from app slash common.

09:56.370 --> 09:59.610
So let's go ahead and update our imports here and we'll also add the.

09:59.650 --> 10:02.260
Rate charge data from apps common.

10:02.260 --> 10:10.540
So we'll go ahead and call this the notification service which will be of type client proxy from nestjs

10:10.540 --> 10:18.220
microservices and of course make sure that this is also private read only so we can use it in the class

10:18.220 --> 10:18.610
here.

10:18.610 --> 10:23.710
So like I said, right after we create this payment intent and we actually successfully charge the user,

10:23.710 --> 10:27.550
that's when we want to actually emit the event to the notification service.

10:27.550 --> 10:31.630
And like I said, we don't need to wait for a response from the Notification Service.

10:31.630 --> 10:34.300
We'll just send this off and let it handle it.

10:34.300 --> 10:41.710
So to do this we can call this DOT notification service dot Emit, and we know we need to specify the

10:41.710 --> 10:42.640
pattern here.

10:42.640 --> 10:45.880
If you remember, the pattern here was notify email.

10:45.880 --> 10:52.480
So let's go ahead and add, notify email, and then we have the data where we can specify the email

10:52.480 --> 10:52.990
here.

10:52.990 --> 10:58.380
Now, right now we actually aren't even providing an email to the payment service.

10:58.390 --> 11:00.310
Let's go ahead and change this.

11:00.310 --> 11:00.700
Okay.

11:00.700 --> 11:08.230
So in order to receive the email in the payment service, we know we're sending the Create charge request

11:08.230 --> 11:14.230
from the reservation service when we actually create a new reservation and we already have access to

11:14.230 --> 11:22.420
the user in our reservations controller thanks to our JWT auth guard and our current user decorator.

11:22.420 --> 11:29.680
So let's refactor this a bit by instead of taking in the user ID here, let's go ahead and get the entire

11:29.680 --> 11:36.040
user directly and we can destructure the properties we know we want off of it, which will be the email

11:36.040 --> 11:43.420
and the ID and this will come off of the user DTO from app slash common and make sure we have an underscore

11:43.420 --> 11:44.680
ID here as well.

11:44.680 --> 11:48.820
And I'll also go ahead and rename this variable to user ID.

11:49.030 --> 11:52.840
So we're still providing the user ID in the reservations repository.

11:52.870 --> 12:00.160
However, now instead of just passing in the Create Reservation, DTO dot charge, which we know is

12:00.260 --> 12:03.500
the card in the amount, we will also include the user's email.

12:03.500 --> 12:05.750
So let's go ahead and create a new object here.

12:05.750 --> 12:12.320
We'll spread the Create Reservation DTO charge and then add the email property here.

12:12.320 --> 12:17.510
Now go back to the reservations controller and instead of passing in the underscore ID, we'll pass

12:17.510 --> 12:18.800
in the whole user object.

12:18.800 --> 12:25.340
So now in the payments controller, we want to update the DTO for Create charge method to include the

12:25.340 --> 12:25.970
email.

12:25.970 --> 12:32.720
However, right now we're using the shared Create charge DTO from our app slash common folder and we

12:32.720 --> 12:35.330
don't want to add the email to this base.

12:35.330 --> 12:41.840
Create charge DTO Instead we can create a new DTO that's specific to the payment service and extend

12:41.840 --> 12:48.740
this create charge DTO to get the card and amount properties with the validation and add our own email

12:48.740 --> 12:49.820
property on top of it.

12:49.820 --> 12:52.310
So let's go ahead and do this in the payment service.

12:52.310 --> 13:00.710
I'll go ahead and create a new DTO in the DTO folder called Payments Create Charge dot DTO, and this

13:00.710 --> 13:08.990
will be a class called payments Create Charge DTO and importantly, this is going to extend the create

13:08.990 --> 13:13.040
charge DTO from app slash common.

13:13.400 --> 13:17.960
So again, we're going to inherit the existing properties, the card and the amount, and now we can

13:17.960 --> 13:25.520
add the email field of type string and specify that this should be an email here from class validator.

13:25.520 --> 13:31.250
Now in the payments controller here, instead of using the Create charge DTO, we will use the payments,

13:31.250 --> 13:34.940
create charge, DTO we can delete the unused import.

13:34.940 --> 13:41.210
And now when we pass our data to the create charge method and make sure we import the payments, create

13:41.210 --> 13:47.630
charge DTO instead where we know we have the card amount as well as the email, and now we can properly

13:47.660 --> 13:51.530
emit the notify email event here to the specified email.

13:51.530 --> 13:54.320
We'll make sure all of our containers are started up.

13:54.320 --> 14:02.870
And now if we firstly log in to get a JWT cookie and create a new reservation, we wait for the reservation

14:02.870 --> 14:08.750
to get created and in the logs we should now see the notification service correctly console logging

14:08.750 --> 14:15.500
out our email so we can see that we're sending off the email correctly from the reservation service.
