WEBVTT

00:00.050 --> 00:03.650
Okay, so we're ready to get started building out our common module.

00:03.650 --> 00:08.030
And the first part of our common module is going to be our persistence layer.

00:08.030 --> 00:14.480
So working with a database and working with an ORM so that we can interact with the database and save

00:14.480 --> 00:16.910
entities in our microservices.

00:16.910 --> 00:21.650
So we're going to use MongoDB for our database layer.

00:21.650 --> 00:26.510
And we're going to build it in a very abstract way so that we could potentially swap the database out

00:26.510 --> 00:29.780
with a SQL database using something like type ORM.

00:29.780 --> 00:33.220
So we're going to build this in a very generic way, a very abstract way.

00:33.230 --> 00:34.640
Follow best practices.

00:34.640 --> 00:36.770
So let's jump right in on the command line.

00:36.770 --> 00:39.440
We're going to need to add a few dependencies.

00:39.440 --> 00:46.580
So I'm going to run npm install nestjs mongoose and then mongoose itself here.

00:46.580 --> 00:48.830
So go ahead and install these dependencies.

00:49.520 --> 00:55.820
So in addition to adding our database module here we're also going to add our configuration module which

00:55.820 --> 01:00.290
is going to allow us to read in environment variables using a dot m file.

01:00.290 --> 01:04.520
Using the dot env package is what Nestjs uses under the hood.

01:04.550 --> 01:09.980
But this is going to make it so that we read in environment variables, and we can change these variables

01:09.980 --> 01:11.390
depending on where we're running.

01:11.390 --> 01:17.660
If we're running locally or in production, we can change that out for different values like our MongoDB

01:17.690 --> 01:23.960
Uri and other configuration variables we will need later on as we build out our microservices.

01:23.960 --> 01:30.560
So to add that, we'll run npm install nestjs slash config.

01:30.860 --> 01:33.590
Okay, so now we have all the dependencies we actually need.

01:33.620 --> 01:38.390
We can use the nest CLI again to actually generate our common modules.

01:38.390 --> 01:46.130
So we'll use nest generate module and then do dash P where we specify the project we want to pass in.

01:46.160 --> 01:52.490
Of course if we go to our nest cli json we can see the list of projects we can add things to.

01:52.520 --> 01:56.900
In our case of course we're going to add to our common library right now.

01:56.900 --> 02:00.590
So let's add the common project here.

02:00.590 --> 02:04.160
And of course make sure we also add the name of the module.

02:04.160 --> 02:07.280
In this case we will call the first module database.

02:07.280 --> 02:13.460
So now we can see that the database module has been created and our common module has been updated.

02:13.460 --> 02:17.630
So if we go back to our code editor we can see that empty database module.

02:17.630 --> 02:19.790
And then our common module is updated.

02:19.790 --> 02:25.040
So I don't actually want a common module or any of these other common files out of the box.

02:25.040 --> 02:31.850
Because each of our independent microservices will import the common modules they need and only the

02:31.850 --> 02:35.030
ones they need, and also configure them independently.

02:35.030 --> 02:37.520
So we don't need any common module here.

02:37.610 --> 02:43.850
Instead, our microservices will import the database module individually with options.

02:43.850 --> 02:49.520
So now that we've created our database module let's do the same thing for our config module.

02:49.520 --> 02:53.960
So this config module is going to be a wrapper around the Nestjs config module.

02:53.960 --> 03:00.560
And so now inside of the config module we can actually set up the imports array here.

03:00.560 --> 03:08.510
So our imports array is going to call the nestjs config module and call for root on it.

03:08.510 --> 03:16.730
And so of course we are going to have to import the config module from Nestjs config.

03:16.730 --> 03:24.230
And we're going to put it in as nest config module here so that it doesn't conflict with our config

03:24.230 --> 03:25.070
module.

03:25.280 --> 03:30.920
And the reason why we're abstracting our own config module and wrapping it around the nest one is because

03:30.920 --> 03:36.890
if we were to change the underlying configuration module, in this case the nest one, we only need

03:36.890 --> 03:37.970
to do it in one place.

03:37.970 --> 03:43.070
So it's always a great idea to try to abstract these third party dependencies when we can.

03:43.070 --> 03:47.420
And that's exactly what we're doing with these modules in the common library.

03:47.420 --> 03:54.110
So now by calling nest config module for root, we are telling the nest config module to load in any

03:54.110 --> 04:02.420
environment variables that we have in memory, and also to read in any dot m files we have in our directory,

04:02.420 --> 04:08.330
which will be super important later on when we use the config service to read in these environment variables.

04:08.330 --> 04:14.180
However, for now we can leave things alone and go back to our database module where we can prepare

04:14.180 --> 04:14.810
to initialize.

04:14.810 --> 04:20.660
So before we initialize the database module, make sure we go back to our terminal here and make sure

04:20.660 --> 04:25.160
we start up our development server in dev mode by running npm start dev.

04:25.160 --> 04:30.110
So we start listening to changes and make sure that our app starts up okay.

04:30.110 --> 04:38.000
We can already see a couple of errors coming from the terminal here on our index.ts, which makes sense

04:38.000 --> 04:40.850
because we deleted our common files.

04:40.850 --> 04:43.400
So we just need to delete these exports here.

04:43.400 --> 04:48.890
Now if we go back, we can see that our nest app has started successfully and we can continue building

04:48.890 --> 04:50.480
out our database module.

04:50.480 --> 04:56.240
So if you've seen my videos in the past, you know how easy it is to set up a connection to mongoose

04:56.240 --> 04:59.780
here, all we have to do is add an import to the.

04:59.920 --> 05:07.630
Mongoose module from Nestjs mongoose that we installed earlier and called for route on it, and then

05:07.630 --> 05:12.550
we can pass in the connection Uri for the database.

05:12.550 --> 05:18.430
So if we were doing this for a very small application, a simple one, we could just simply pass in

05:18.430 --> 05:23.950
the connection uri localhost and pass in the name of the database.

05:23.950 --> 05:25.390
In this case sleeper.

05:25.390 --> 05:27.370
And this would work perfectly fine.

05:27.370 --> 05:34.270
And to even test this out we can go into our source folder here and in our imports array.

05:34.270 --> 05:39.820
For our route app module we can add the database module that we just added.

05:39.820 --> 05:46.900
And notice here how when we added the database module, it automatically imported it into the libs folder.

05:46.900 --> 05:51.850
So we want to keep this import nice and clean in case we change the directory structure.

05:51.850 --> 06:00.400
We want to target app slash common because if you remember from earlier we updated our Tsconfig here

06:00.400 --> 06:05.170
with a path section that says if we use app slash common look in the libs folder.

06:05.170 --> 06:10.300
So if we ever change the directory structure, we only need to do it once in our tsconfig here.

06:10.300 --> 06:16.000
And of course now if we come back, we can say that Index.ts is not exporting this module.

06:16.000 --> 06:21.430
So this is going to be important that whenever we want to use something from our common library, we

06:21.430 --> 06:24.190
need to export it from the Index.ts here.

06:24.190 --> 06:28.150
So we're going to export everything from the database directory here.

06:28.150 --> 06:36.550
And then I'm going to add an index.ts to my database directory and export everything from the database

06:36.550 --> 06:37.180
module.

06:37.180 --> 06:43.480
So now if we go back to our root app module in our app, we can see that there's no more errors here.

06:43.480 --> 06:49.210
And now if we go back to the terminal we can see that our nest application is starting up.

06:49.210 --> 06:51.220
However it seems to be hanging.

06:51.220 --> 06:56.080
And that's because currently I don't have MongoDB on my system running.

06:56.290 --> 07:00.670
So I have MongoDB and my system already installed.

07:00.670 --> 07:04.930
I will have another video that goes over how to install MongoDB.

07:05.170 --> 07:12.100
If you do not already have it, we can easily start up the Mongo server by calling Mongo d dash dash

07:12.100 --> 07:18.310
data path and then in this case, my data path where my data will be saved is a folder I created called

07:18.310 --> 07:19.570
data slash db.

07:19.930 --> 07:27.280
You can use whatever you want and once the MongoDB server is running, let's go back to our database

07:27.280 --> 07:28.180
module here.

07:28.180 --> 07:34.780
And if your application still has not connected to MongoDB, if mine hasn't yet, you can try changing

07:34.780 --> 07:41.680
localhost here out for your actual localhost IP 127.0.0.1.

07:41.680 --> 07:48.010
And now if we go back to our terminal, you can see that the mongoose module was successfully initialized

07:48.010 --> 07:54.340
and our application successfully started, which means we have connected to the MongoDB database.

07:54.340 --> 08:01.390
And if we even go back to the MongoDB logs, you can actually see that we accepted a connection on localhost.

08:01.390 --> 08:05.620
And this is the port we accepted the connection from on our NodeJS app.

08:05.620 --> 08:11.260
So now that we've successfully connected to our database, I want to go ahead and refactor how we're

08:11.260 --> 08:15.550
actually providing this connection string to the mongoose module.

08:15.550 --> 08:20.860
Instead of having to hard code this connection string, we want to expose this through an environment

08:20.860 --> 08:26.050
variable, since this connection string will likely be different depending on where we're running the

08:26.050 --> 08:30.580
application, and we want to be able to switch it out through an environment variable.

08:30.610 --> 08:37.480
To do this, we can go ahead and create a dot env at the root of our project, which is a file that

08:37.480 --> 08:43.540
will host all of our environment variables that our application will read in at runtime by default.

08:44.320 --> 08:51.790
So I want to go ahead and specify a MongoDB Uri, which is a name that we'll create to specify the MongoDB

08:51.820 --> 08:56.320
Uri and simply set it to the connection string.

08:56.320 --> 09:02.500
So MongoDB 127.0.0.1 slash sleeper.

09:03.500 --> 09:10.190
So this dot m file is automatically going to be loaded in by our config module, which uses the dot

09:10.250 --> 09:13.940
env package internally to load this dot env.

09:14.390 --> 09:19.630
Now we want to actually refactor this import to utilize the environment variable.

09:19.640 --> 09:27.110
So to do this we'll instead call for route async which is going to allow us to actually inject dependencies

09:27.110 --> 09:28.730
into a factory method.

09:28.730 --> 09:32.210
So this means we can actually get access to the config service.

09:32.210 --> 09:34.660
When we're initializing this mongoose module.

09:34.670 --> 09:39.920
Now Nestjs will automatically make sure that the config service is ready.

09:39.920 --> 09:46.220
By the time the mongoose module needs to be initialized, we simply just need to tell it which dependencies

09:46.220 --> 09:46.970
it needs.

09:46.970 --> 09:52.550
So let's go ahead and do that by first opening up an options object where we're going to go ahead and

09:52.550 --> 09:55.370
specify that use factory property.

09:55.370 --> 10:01.640
So this use factory is going to tell nest how to actually create the mongoose module options.

10:01.790 --> 10:07.580
So this is going to be a function that takes in any injected providers.

10:07.580 --> 10:13.640
So in this case we're going to inject the config service of type config service.

10:14.580 --> 10:17.060
And we import this from nestjs config.

10:17.070 --> 10:19.860
So as we know this is using env internally.

10:19.860 --> 10:21.810
And we'll load that dot env file.

10:22.410 --> 10:26.970
So now in this function we're going to go ahead and immediately return an object.

10:26.970 --> 10:34.680
And this object is the mongoose module configuration which we had before that simply specified the Uri.

10:34.710 --> 10:39.420
However now to get the Uri we can actually use the config service.

10:39.420 --> 10:43.770
And we can call get on it to read in an environment variable.

10:44.280 --> 10:48.240
And then we'll go ahead and pull off the Mongo DB Uri.

10:49.970 --> 10:56.030
Now, finally, we need to tell Nestjs about these providers that we're injecting in the use factory

10:56.030 --> 10:56.640
here.

10:56.660 --> 11:03.970
So to do this we have another property after use factory called inject that we pass to for route async.

11:03.980 --> 11:09.200
And this is the list of dependencies that we need available in order to actually execute this.

11:09.200 --> 11:10.840
Use factory function here.

11:10.850 --> 11:15.500
So we know this will be the config service from nestjs config.

11:16.200 --> 11:22.740
So for root, a async is a very powerful pattern that Nestjs offers us, and it allows us to initialize

11:22.740 --> 11:29.850
these modules asynchronously on application startup and get access to these dependencies like the config

11:29.850 --> 11:30.750
service.

11:30.990 --> 11:37.170
Now finally, we're actually going to need to make sure that we add an imports array to this as well,

11:37.170 --> 11:44.880
and pass in the config module from our local config module, which we know is exporting the config service

11:44.880 --> 11:45.840
for us.

11:45.930 --> 11:51.840
Now next up I want to show you how we can implement validation on our environment variables so we can

11:51.840 --> 11:56.940
tell nestjs about the environment variables we need when the application starts up, or else we can

11:56.940 --> 11:57.920
throw an error.

11:57.930 --> 12:03.090
So this way we always know that we have these environment variables ready that we need to actually run

12:03.090 --> 12:03.810
the app.

12:04.140 --> 12:11.220
In order to do this, I'll stop my development server and install a new package called Joy.

12:12.470 --> 12:17.870
Which will allow us to do schema validation, and then we can go ahead and start our server back up.

12:18.020 --> 12:25.670
And let's go back to our config module, where we can now provide an options object to the nest config

12:25.670 --> 12:29.900
module here and add the validation schema.

12:29.900 --> 12:36.050
And now in this case we can call Joy dot object because we're going to provide an object.

12:36.050 --> 12:41.870
And the first environment variable that we've defined that we need is of course the MongoDB Uri.

12:42.110 --> 12:46.790
So let's pass that in here we can see we get an error about importing joy.

12:46.790 --> 12:53.000
We can resolve this by changing the import statement as import star as joy from joy.

12:53.240 --> 12:59.360
And then now if we go back we can see that nest application starts successfully and we have no issues.

12:59.360 --> 13:06.110
So we can set the MongoDB Uri here equal to joy dot string, which means that this has to be a string.

13:06.110 --> 13:08.810
And we'll say that the value is required.

13:08.810 --> 13:10.940
So now if we go back to the terminal we'll see.

13:10.940 --> 13:11.930
We have no issues.

13:11.930 --> 13:13.970
And our application is still running.

13:13.970 --> 13:20.150
We were to then delete the MongoDB or from our file and then go back to our terminal.

13:20.150 --> 13:25.280
We'll of course have to restart because by default it's not watching the dot env file.

13:25.280 --> 13:32.030
We can see here that we have an error thrown a config validation error MongoDB Uri is required.

13:32.030 --> 13:38.360
So we can see that we are now connecting to MongoDB and providing the connection string via an environment

13:38.360 --> 13:38.750
variable.

13:38.750 --> 13:44.300
Using our config module, we have successfully set up our database module, and we're now ready to start

13:44.300 --> 13:50.960
building out our abstract repository that the rest of our microservices will use in order to implement

13:50.960 --> 13:54.170
simple, reusable and maintainable data access.

13:54.200 --> 13:56.810
Let's jump right in and I'll see you in the next lecture.
