Okay, so we're ready to test out our newly created abstract repository.
And to do that, we're going to go ahead and create our first microservice inside of our mono repo.
The service responsible for actually taking reservations from our users when they want to book a stay
somewhere.
So in order to generate this in the terminal, I'm going to use the nest cli and run nest G for generate
app and we'll call this microservice reservations so we can see that we have a newly created apps directory
here with a default directory with our existing source folder from before and the important reservations
folder which has its own source directory and set of default files as well as its dedicated config that
will extend our root TS config.
So if we also go ahead and look at the nest CLI so we can see we've added these two new applications
into our nest client JSON and so we're not actually going to keep this sleeper directory here, the
default one out of the box so we can actually go ahead and remove this and let's go ahead and change
our route here to instead of Apps Sleeper, we'll change it to apps Reservations, which will be our
default project.
And also go ahead and change here the TS config path and make sure we pass in app slash reservations.
And finally we have the source route property here which we can see points at the default project in
a mono repo.
So as I said before, our default project we will just use the reservations.
So swap that out here and then finally we can go back and actually delete the sleeper directory altogether.
And so now we just have our apps reservations directory to be able to go back to our terminal and start
things back up using NPM, start dev and you can see our application starts up fine.
We are not seeing the Mongoose module being initialized anymore and that's because of course we've gotten
rid of the original source directory and we will have to re import it in our new reservations microservice.
And that's exactly what we're going to do by going into the source directory and inside of the reservations
module.
We know of course, that we are going to pass in the database module and make sure we change the import
here to be at app slash Common.
And so now if we go back to the terminal, we can see that the Nest app starts up and the Mongoose module
is initialized and everything's all right.
And of course I still have Mongo running in another tab.
So in order to add some default CRUD functionality to our reservations service, we can also use the
nest Clive and have it generate a resource for us called reservation and make sure we generate this
in the reservations project.
And we can see here that it asks us which transport layer we want to use.
We're going to use a variety of transport layers in this course, but for now we're just going to start
off with a default rest API and then it asks, Would you like to generate CRUD entry points?
We will go ahead and say yes.
And so this is going to go ahead and create some boilerplate code that's going to save us a lot of time.
So after our command here completes, you should see we have a bunch of new files have been created
for us.
And so if we go back into VS code, we now have a new directory, our reservations directory, where
we have a set of files here that will allow us to accomplish CRUD functionality.
So first off, here we have our reservations controller.
So this will be a controller with the reservations prefix that will have a reservation service and we'll
call all the CRUD functions on it, including being able to create a new reservation, find all, find
one update and remove.
And you can see here we're taking advantage of these nestjs decorators in a controller so that these
routes are mapped to get patch, delete and post routes.
And we're also extracting the body here on some of these calls.
So in our Create Reservation request here, we can see we have an automatic DTO already defined for
us that will have no properties by default, but we will fill out eventually and for find one we have
the param to get the ID of the reservation for Patch.
We do the same and take an update reservation DTO, which is just going to extend a partial of our create
reservation.
And then lastly, we have the delete route here that takes the param and removes the reservation.
So we're going to continue building this out.
But it's nice that we have all of this boilerplate already complete and of course we have a reservation
service here that is just filled in with stub methods.
So what we're going to do is we're going to go ahead and take all of the files in this reservations
directory and move them up into the source directory.
So when we do this, it'll ask us to replace the existing files.
I'll go ahead and replace them.
And now we're ready to start actually using our.
Our abstract repository so we can fill out this reservation service and actually interact with a database
directly here.
Go ahead and open up the reservations module because since we replaced this with the Nestjs command,
we're going to have to re add our imports array here and add the database module.
I'll go ahead and change the import here to app slash common and then we can go ahead in our source
directory and create our actual reservations dot repository, dot ts.
And so this will be an injectable class because we will be injecting this into our reservation service.
So we'll go ahead and export our class here called Reservations Repository.
And this is going to go ahead and extend that abstract repository that we created before.
And I'll go ahead and change this to app slash common.
And you can see here that the compiler is complaining because we have not actually exported the abstract
repository.
So make sure in our source folder we open up the index.ts and open up the database Index.ts and actually
export everything from abstract repository.
So if you recall back in our reservations repository, the abstract repository here expects the document
to be passed in which extends the abstract document that has the underscore ID, which is of type object
ID.
So we need to pass in the reservation schema here.
So to do that, I'm going to go ahead and rename the entities folder here.
I like to just call it models and inside I will change the reservation dot entity here to be reservation
dot schema and we're going to go ahead and define the schema for what a reservation document actually
looks like.
So to do this, we'll go ahead and add a decorator here called ADD schema from Nestjs Mongoose.
And I'm going to pass in an options object here and set the version key to false.
I don't want versioning on my documents in this project.
And then we're also going to change the reservation here to be called the reservation document.
And we know, of course, this will actually extend the abstract document that we can import from the
app slash common.
And then inside we're going to define the properties that exist on a given reservation.
We already know we'll have the underscore ID, so we'll continually come back and add to this document
as we build out our microservices.
However, for now we can add some basic information about this reservation.
So the first thing I want to add here is a timestamp, which will be a date and actually be the time
that this reservation was created.
I'm also going to add a start date, which will be another date here, which will be when the reservation
begins, and then we'll add an end date, which will be when the reservation ends.
Now we don't have any idea of authentication or users quite yet.
However, I know eventually that I'm going to want to associate this reservation with a given user ID,
so this will have a type of string.
So next this reservation is going to be tied to a particular hosts user so that the user who actually
posted this document, we want to be able to associate it back to them.
Okay.
And lastly, this reservation is going to be for a given place in our application.
Now, places will be where you actually stay for this given reservation and places will be its own microservices
in our application.
However, for now, we want to be able to associate a given reservation with a place so we will label
it place ID of type string so that we can associate it with.
Okay.
And lastly, we're going to have a property to actually associate this reservation with its invoice
in our system.
So we'll have another microservice that actually takes care of invoicing and billing the user.
And we want an ID to be able to associate this reservation with that invoice.
So we'll assign an invoice ID here and this will also be of type string.
So for now, this is everything we need to create our reservation document.
And we're getting an error here that the abstract document was not exported.
So we'll have to go back to our index.ts for our database and make sure we export everything from the
abstract schema here so that we satisfy this.
Now, back in the reservations repository, we can finally provide here for some type information the
reservation document that we just created.
Okay.
So next we need to actually tell Mongoose about this document.
And in order to do that, we need to decorate each of these properties here with the app prop decorator
from Nestjs Mongoose.
So after we've done that, we need to actually export a new const here called reservation schema.
And this is going to be schema factory from Nestjs Mongoose dot create for class and then pass in the
reservation document that we just created.
And you'll see where we use this soon enough.
So back in the reservations repository, there's a bit more work we have to do.
We need to actually create this protected read only logger and set it to new logger from Nestjs common.
And we can pass in the name of the repository here to give it some context.
So now that we have that logger that the abstract repository can actually use, we need to define a
constructor here where we actually inject the model from Mongoose, which of course we know the abstract
repository will need to actually use and manipulate the documents.
So in order to get this, we need to call at inject model from Nestjs Mongoose and then pass in an injection
token that we will soon define.
So we're going to choose the reservation document.name as the token here, and then we can call this
variable reservation model which will be set to model from Mongoose.
And then pass in the reservation document.
So now all we have to do to give this to the abstract repository is called super here and then pass
in the reservation model.
Now finally, we can go back to our reservations module here and for our providers array, we're going
to pass in the newly created reservations repository.
So we can actually inject it in our application.
Now if we go back to our terminal where our app is running, you can see that it's complaining that
it can't resolve the dependencies of the reservations repository.
So it's essentially saying that it doesn't recognize the reservation document model we're trying to
inject.
And the reason for this is that we haven't actually told Mongoose about this schema here.
Now, in order to accomplish this, we'll go back to our Libs common folder.
In the database module, we're going to add a new static method here called Static for feature.
And this is going to take a variable here called models, which will be a model definition from Nestjs
Mongoose array.
And all we're going to do in here is return Mongoose module dot for feature where we pass in these models.
And so we're just abstracting this schema initialization process away from the implementation.
In this case, it'll be our reservations module.
So to actually use this, we'll just call database module for feature and pass in an array of schemas
here.
In our case we only have the one, so it's a single object where we provide the name and this name is
the injection token that we use to inject this model.
And of course, if you remember in our reservations repository, this was the name of the reservations
document.
So we'll provide that name here by calling reservation document.name, and then finally, we need to
provide the actual schema.
And in this case, this is going to be the reservation schema that we created in our reservation schema
file here.
This create for class variable.
So now if we go back to our terminal, we can see the app starts up successfully now.
And now finally we can go back to our reservations service and actually add a constructor here and finally
inject the read only reservations repository.
Of type reservations repository.
And now we can finally use this repository to fill out these CRUD methods and actually persist data
to our MongoDB database.
So in the create function here, instead of returning the string.
We'll return this dot reservations repository, dot, create and pass in this DTO.
Now this is going to complain because of our type checking that the Create reservation DTO is missing
a number of properties that exist on the reservation schema.
So let's go ahead and take a look at the reservation DTO, which by default is empty here.
So let's go back to the schema itself and we can just copy all of these properties and paste them into
the DTO.
Now we're not going to need the time stamp from the user because we'll generate that on the server.
We'll keep the start date and end date and get rid of the property keys here.
I'm also going to get rid of the user ID.
This is going to come off of the JSON web token that the user will provide for authentication once we
implement that.
So we can just leave it empty for now and we'll hardcode it and then finally we'll have the place and
invoice ID.
So now back in the reservation service, instead of passing in the DTO, we can spread the DTO and then
provide the time stamp as a new date.
And then the user ID, like I said, will be coming off of the JSON web token that the user will eventually
provide for.
Now we'll just hard code this to one, two, three.
So now that our create function is done, we can fill out the find all pretty easily.
We'll just return this dot reservations repository dot find and pass in an empty filter here to get
all the documents.
Find one here we can call this dot reservations repository dot find one.
So by default the ID passed in is a number from Nestjs.
However, there should be a type string which matches our underscore ID.
So now for our find one for our underscore ID, we'll just pass in the ID field here and we can change
the name to underscore ID So now we can find a reservation by its ID.
Now an update will do something similar.
We'll change this to underscore ID of type string.
And we will return this dot reservations repository.
Find one and update.
So our filter query here will be for the underscore ID.
Then for the second argument, we'll actually provide the update itself.
In this case I want to use the dollar sign set property here which will allow us to override existing
properties on this document.
So now we can actually provide the update reservation DTO, which could potentially contain anything
that already exists on the Create Reservation.
DTO because we're extending it here as a partial type.
And finally, for remove here, we can change this to a string as well.
The underscore ID and call this dot reservations repository dot find one and delete where we just pass
in the underscore ID.
Now lastly, back in our reservations controller here, all we have to do is just get rid of the plus
for the ID here.
So that keeps TypeScript happy and we can see we have no errors in our terminal, so we're ready to
test out our new API.
And I'm in Postman here and I've have the URL set to localhost 3000 slash reservations where if you
remember this is where we defined this controller to live on.
So we're going to test each of these routes off.
First will be the post call to actually create the reservation and we pass in a JSON body here with
all of these properties.
So we have the start date, end date, place ID and invoice ID.
So if I execute this post request, you can see we get a 201 created response back and we get the newly
created document back with all of our information.
Next, let's actually try to get all of the reservations with this get find all So we'll call get.
And you can see I have an array of reservations I've created.
I've created this one twice so we can see it created both times here and back and back in this array
at two response 200.
And now to test out our find one route here we will provide the actual ID as part of the route and you
can see we extract that id using the params decorator.
So we're going to take an ID of one of these documents here and add it to the route here.
So now if we get this single document, we can see it's pulling back that single document based on the
ID we provide.
Next, let's try to update a single reservation using the patch route where we have the ID and then
the update command so we can go back here.
We can keep this existing ID, change this to patch, and now I'm just going to change the start date
only.
I'm going to say it starts on the 22nd here instead of the 20th.
And if we send this off and now you can see the start date is changed to the 22nd.
If I launch a get request for this reservation, again, you can see our newly updated start date.
So Patch is working great.
And then finally for delete we provide the ID as a parameter as well.
So let's try this out by calling delete route on this reservation and it has succeeded with 200.
Okay.
So now if we run a get for this reservation, we should expect to see we get that 404 that's part of
a repository where we throw this error.
If it's not found, which is exactly what we'd expect to see because this reservation no longer exists.
So in this lecture we've implemented full CRUD functionality.
However, one thing I want to add right now is validation.
Right now, if I try to send a post request to create a new reservation, I can just provide total garbage.
I can say the start date is 32 and we don't provide any other properties.
If I send this request off to the database, it actually succeeds.
And you can see here that the document gets created without some very important properties.
And this is not what we want.
We want to provide some validation so that the user can't just give us whatever they want to our server.
Let's implement this in the next lecture.