We had already developed a full-fledged REST API server
using Express and MongoDB as part of this course.
In order for that server to be able to communicate meaningfully with our client,
we will make a few minor adjustments to it
so that it returns the right kind of data so that
our client implementation can work more
efficiently with the data returned from our server site.
So, to do that,
let's work on a few adjustments to our server site in this exercise.
Before you start this exercise,
I am assuming that you have not done
the previous lesson on integrating the angular client and
the server because you are doing this lesson coming through the React specialization.
So, the changes that I will make to the server will assume that
the version of the server that you're modifying is before the previous lesson.
In case you have done that lesson on angular client,
some of the changes that you have done to your server will be repeated again
in this exercise so you can skip over that part of the changes.
Go in to our server in the editor.
Before we start working on the server,
I would suggest that you download all the images that I have
provided as a zip file in the exercise resources called images.zip.
Unzip the file and then obtain all the images from there and then copy those images
into the public images folder in our server.
So, you see that here I have copied all the images into my public images folder here
already because our server is the one that is going to
serve up all these images for our client application.
Next, we go to the CORS and adjust the whitelist here.
So, for our React client application,
if we started up with the yarn start command,
it runs at your computer name:3001.
So, any request coming in from our location to
the server will carry that as the origin there.
So that is why I am going to add that into my whitelist so that
any CORS problems will be addressed automatically.
So, going into the cors.js file in my whitelist here,
let me add in the http://my computer's
name:3001 and this is
the origin from which my client will
be originating the requests that come to this server.
So, that way my CORS would not cause problems for my client.
Next, we need to update a few of the routes to
handle the query parameters and also a few minor other adjustments.
Let me start with the promoRouter.js file.
That is simple to get updated.
So, going into the promoRouter.js file,
in the promoRouter file for the get request that we get
here instead of doing promotions find with an empty JavaScript object,
here I would supply the req.query as the parameter to the promotions find here,
same thing with the leader router also.
So, let me go to the leaderRouter.js file.
In the leader router also,
here where you find Leaders.find with the empty JavaScript object instead
replace that with the req.query so that the query parameters will be passed in.
So, this is where we will pass in the featured:true as the query parameter here.
Now, having adjusted these two,
let's now work on the dish router.
So, go into dishRouter.js file,
even in the dish router also the same update here.
So, go into this Dishes.find in the get method here,
change that to req.query.
So, with this, my dish router update has been completed.
So, we have now updated the promo router, the leader,
and the dish router,
then we will move on to update the favorite router.
Now, you would have implemented the favorite router as part of your fourth assignment.
Now, in the favorite router,
you will see that for the favorite router,
I'm not showing you the remaining part because that
you should have done as part of your assignment.
First, let me draw your attention to the get method for the favoriteRouter.route:dishId.
Now I'm going to use this get method to just check to ensure that
the specific dish with the dish Id is already a favorite for the user.
So, instead of simply saying getoperation.supported,
I am just going to leverage the presence of this get operation and then we'll say,
Favorites.findOne and we'll say user: req.user._id.
So, we will find the favorites for that particular user and then we'll say then
favorites and catch error next.
Then similarly here, we will add in the err here, next err here.
So, inside this then,
when we get the favorites,
then we will check if not favorites.
So, if there are no favorites for
this user then obviously the dish that we are checking for doesn't exist,
so we'll return res.statusCode 200,
setHeader, Content-Type,
application/json and then we'll return saying exists false.
What we are specifying here is that if they get is done to this end point with a dish Id,
this exists flag here will be set to true if this dish is part of my favorites.
If this dish is not part of my favorites,
I will set there exists flag to false.
So here, you see that since I don't have any favorites so
exists should be automatically false at this point.
So, we'll say exists false and then we will return the favorites here.
Well, obviously, in this case the favorites would be null at this point.
Otherwise, so which means that favorites is not null,
so we'll say if favorites.dishes.indexOf.
So, we're going to be searching for req.params.dishId.
So, we're going to search this favorites dishes array to
see if this dish exists in there and if it doesn't exist,
obviously this will return a negative index here.
In that case also,
I will return exactly the same as here.
So, if it returns a negative index then that means that even
though this particular user has a set of favorites,
this specific dish doesn't exist in
the list of his or her favorites so that's why it'll return exists false here.
Now, otherwise that means that the dish exists in the list of favorites.
So, in this case,
I will return status code 200 exists is true.
So that way, when the user performs a get operation on this endpoint with
the /favorites/dishId where the dish Id is supplied as the parameter here,
as the request parameter here,
then we will check to see whether that dish exists in the favorites.
If none of the favorites exists for this user then we'll return an exists false.
Similarly, if the favorites exists but
that particular dish doesn't exist in the favorites then we'll return false,
otherwise we will return true.
So this exists flag can be used by my client to check to see if this dish is
part of the list of favorite dishes for this user or not.
Also while we are in favorites,
whenever we make any changes to the favorites,
we want to be able to populate the user and dishes information,
the favorites, before we return.
For example, in the post that we do,
when we save the favorites then at this point,
we would like to first do favorites.
FindById, so because we just made the changes we'll say favorite_id
and we'll populate both the user and also
populate the dishes in the favorites.
Then when the favorites is returned,
we'll return that favorites instead.
So, let me make this change here.
So, we will cut this out from here and then inside the then,
we'll return the favorites.
After we save the favorites,
then we'll search for it,
for the favoriteById and then return
that favorite here so we'll say then favorite return and status code.
This change we should make.
If you have already implemented this in your favorites,
then you don't need to make this change.
But what we are doing is whenever we make changes to the favorites,
we'll populate both the user and dishes information and then return this value
because our React client expects this to be there.
Now, the same kind of change,
we will need to make variable b, save the changes.
So in the post here,
we'll make a change to that,
so we'll say favorites.save and then we'll do favorites.findById and make that change.
Similarly, under the dish id,
also in the post,
you will be similarly, whenever you make changes to the favorites,
will first look for it and then populate both the user and dishes and then return it,
and then similarly in the else part.
So, you must have implemented this in your fourth assignment.
So, make this additional change where you will populate
the user and dishes before you return the value.
Also with the delete,
we'll do the same changes here.
So, you notice that in the delete,
I have already made this change here.
So, after we save the changes to the favorites,
we'll then search for the favorites and then
return after populating both the user and dishes and the favorites.
This is what our React client expects us to do.
So, even for the delete,
we'll do the same changes.
Now, with this, my favorite router is updated
so we'll proceed ahead to update users.js next.
Finally, we'll update the users.js file.
Now, in the users.js file we need to add in
another router.options field here,
because sometimes a post request as you saw
with the login will send the options first to check,
especially with cars, whether the post request will be allowed.
So that's why we will check course with options here and then
we'll simply return
a status message
of 200 in response to that.
For any endpoint under users if we receive the options,
we'll simply return a status 200 here.
Now the login function that we had implemented earlier,
we had simply done passport.authenticate
local here and the we checked for the remaining values here.
Now, this passport.authenticate local,
if the user doesn't get authenticated,
it simply returns an unauthorized in the reply message.
Now that may not be very meaningful for the client side to display this information,
so that is why we will enhance
this router post login method
such that the authentication will return more meaningful information at this point.
So to do that,
we are not going to be doing the passport.authenticate in here,
instead we will take.
So, let me remove that from there and then you will see
how I will update the router post here.
So, we'll see course with options and then we'll include the req,
res and next here.
Inside this req, res and next here,
passport.authenticate will call this with local.
Now, when we call this with local,
if authentication error occurs,
the passport.authenticate can be made to return
the error value and also it will return the user if there is
no error and a third parameter called info
which will carry additional info that might be parsed back to the user.
This error will be returned when there is
a genuine error that occurs in the passport.authenticate.
But if the user information
is sent into passport.authenticate but the user doesn't exist,
then that that is not counted as an error.
Instead, it'll be counted as user doesn't exist and
that information is parsed back in the info object that comes in.
So, the error will be returned when there is
a genuine error that occurs during the authentication process,
but the info will contain information if the user doesn't exist.
So, the passport.authenticate is passing back a message saying that
the user doesn't exist or either the username
is incorrect or the password is incorrect and so on.
So, that information will be passed in in the info message.
Now we will see how this is useful to
us when we look at the client side a little bit later.
So, in this situation,
we will handle this as follows,
and not only that when we call this passport.authenticate,
we also need to pass in a req,
res, next as the three parameters to it.
So, this is the structure when you need to call passport.authenticate and expect it to
pass you back information like this as a callback method here,
so you also need to supply this req, res,
next right there too.
Now, if this occurs,
so we'll say if err,
so if there's an error that occurs,
we'll say return next err and then let
the error handler of our express router and take care of that.
Now, we will consider other situations, if not user.
So, if we have reached this point,
then that means that it was not an error that occurred
but instead perhaps the user could not be found.
If the user is not found,
then the user here will be set to null in this case.
So, in that situation,
if the user doesn't exist,
then we need to be able to pass information back to the server side.
So, what we will do is we will pass in this information in this format.
So, I'm going to cut this out from here and
then paste it in here and then we will edit this.
So, if the user is null,
then we will send back a status code as 401 which means
unauthorized and then we will send back information success false,
and then we will not be passing back the token,
we'll pass back the status message.
So, here we'll say
'Login Unsuccessful' and then the third information,
we will pass this info that object that we received here as
the third part in the reply message that we send back from our server here.
So, the success flag will be set to false,
the status will be set Login Unsuccessful and
the error information that is passed in the info will be passed back.
Now, note that this situation will occur if
either the username and the password is incorrect,
and so this is not an error in the error sense but the fact that
the authenticate could not find either the user or the password of the user is incorrect.
So, that information will be encoded into the info that comes in and so that I will
pass back as an error to my client side.
The otherwise part
is handled as req.logIn.
So, if this is successful,
the passport.authenticate we'll add this method called req.logIn to the user.
So, at this point,
we will just simply pass in the user object that we've obtained.
So here, if we have reached this point,
then that means that the user object is not null and also no error occurred,
so that means that the user can be logged in.
So, we'll say err,
we'll try to login the user.
So, we'll say if err and
then we will pass back the same kind of error information that we did here.
So in this case, if error,
then we will pass back a status code as 401 and we'll say success
is false and status as Login Unsuccessful,
and then the error information,
instead of the info,
we will pass in 'Could not log in user".
So, that is the message that we'll pass back here if the error occurs.
Otherwise, we would be down below here.
So, at this point,
we would be able to generate the token.
So, if we have reached up to this point,
that means that the user has successfully logged in,
and so we can now generate the token.
So, we'll generate the token based upon the user's ID,
and then we'll pass back the token back to the user.
So, here, we will say var token,
and then we can say res.statusCode is 200 and then res.json success true,
so, which means that the user successfully logged in.
So, the status would be login successful.
Then, the third part,
instead of the error,
I will pass the token back to the user.
So, we'll say token,
this token which we just obtained earlier.
So, that token will be passed in as the token property of the reply message.
So, here, notice that the success is set to true, so,
which means that the user successfully logged in,
and so the user can proceed further at this point.
This has to be done inside the req.logIn here.
So, at this point,
we will close the req.logIn.
So, notice that this is inside this req.logIn here.
So, in there, we will pass these three back.
So, let me just indent these three lines in.
So, that is how we would handle the user's logging method.
So, again, reviewing this code one more time.
So, we'll do router post,
but instead of doing passport authenticate right there,
we will say req, res,
next, and then inside here,
we'll do a passport authenticate for the local,
and this authenticate will pass back.
So, we can supply a callback function to that,
and this callback function will return either the error,
the user, or the info here.
So, if it is an error,
we'll just allow the express error handler to take care of that.
If the user is null,
then that means that the user login was unsuccessful,
and the reason for that will be in the info.
So, that will pass back as the info error in the reply message here.
If we come up to this point,
then the user is successfully verified.
So, then we will login the user.
So, the passport authenticate,
we'll add in this method called login to the req, the request message.
So, we can call the login with the user.
If this returns an error,
then we will return the error here appropriately.
If not, then we will have reached the point where the user is successfully authenticated.
So, we can generate the JSON Web Token here and then return
the JSON Web Token to the user to confirm that the user is successfully logged in.
So, that is the set of steps that we're going to use here.
Now, the reason why I do a more elaborate way of handling it is that
I want to distinguish between the situation where a genuine error
occurs during the authentication process as opposed to the situation
where the user name is invalid or the password is invalid.
So, those two cases will be handled by this situation,
where the info will carry the information back to us.
So, that's not a error per se,
but that's situation where the user is
not a valid user or the user's password is not valid.
So, that's how we will handle the user's login process.
In addition, I will add in
one more method here called checkJWTToken.
It is quite possible that while the client has logged in and obtain the JSON Web Token,
sometime later, the JSON Web Token may expire.
So, if the user tries to access from the client side with an expired token to the server,
then the server will not be able to authenticate the user.
So, at periodic intervals,
we may wish to cross-check to make sure that the JSON Web Token is still valid.
So, that is the reason why I am including this,
another endpoint called checkJWTToken.
So, if you do a get to the checkJWTToken by
including the token into the authorization header,
then this call will return a true or false
to indicate to you whether the JSON Web Token is still valid or not.
If it is not valid, then the client-side can initiate another login for
the user to obtain a new JSON Web Token if required.
So, to do this,
we'll say cors.corsWithOptions and req,
res here as expected.
In here, we'll say
passport authenticate jwt
and session: false,
and this would return err, user, info.
So, recall how we use the passport authenticate earlier.
So, we call the JWT with session false here.
So, earlier here, we say passport authenticate local.
So, this is for the local authentication.
So, this is for the JSON Web Token authentication.
So, when we call that,
then since that is going to verify the JSON Web Token, so we'll say,
if err return next err,
and then let the express error handler take care of that situation.
Then, we'll say, if not user,
if the user doesn't exist, then similarly else.
So, which means that if the user object was
found from the JSON Web Token and then loaded onto the req.user,
then that means that the user is a valid user,
and so can be allowed to proceed further.
Otherwise, we're going to say that the user doesn't exist.
So, we need to inform that the JSON Web Token has expired.
So, at this point,
we'll send a res with
a status code of 401.
So, unauthorized, setHeader, Content-Type,
application/json, and then we'll return res.
Res.json will say status JWT
invalid and then,
we'll return a flag called success falls and then,
we'll return the info that we obtain if the user is
not authenticated as the error at this point.
Otherwise, that means that we reached this point,
then the user is a valid user.
So, in this case,
let me just copy that code here,
we'll be sending a status code of 200 and then the res.json,
will send JWT valid and successful being true.
The third part, we will send the user's information.
So that way, when this endpoint is called with the get method,
then this will verify whether the token is valid or not.
If the token is valid,
then you will receive this reply and from the success flag in the reply,
you can check to see whether the jsonwebtoken is valid or not.
This is useful on the client side.
Now, this passport authenticate here will have to be supplied
with req and res as the two parameters here.
So, that's how we call the passport authenticate.
So, notice that whenever you call
passport authenticate and expect this callback function in here,
you need to append to this point req.res to the passport authenticate at the back here.
In our rest API server,
we had implemented our comments in such a way that the comments
formed sub-documents inside the dishe's document,
so they buy every dish enclosed its own set of comments.
But the way we implemented our React client is
such that the comments are kept independent of the dishes,
and the comments themselves carried the corresponding dish ID.
Now, these are two different ways of
implementing the server-side as well as the client side.
In the Angular application that we are implemented in our Angular specialization,
we had used the sub-document method for
handling comments in our Angular client application.
So, the rest API server was
implemented in such a way that it was more suitable for the Angular client.
But for the React clients since we kept the comments independent of the dishes,
and then use the dish ID inside the comment,
so we need to restructure our rest API server,
so it's that we have a separate comment endpoint independent of the dishes endpoint.
So, we need to restructure our code in the server
to introduce the /comments REST API endpoint at this stage.
So, to do that,
let's go ahead and implement a new model called as comment.js.
So, going into the models,
let me implement a new file named comments.js.
In the comments.js file,
we're going to move the commentSchema from the dishes.js
file into the comments.js file and then remove it completely from the dishes.js file.
But before we do that,
we need to copy the mongoose and the schema from here,
so let me just copy this from dishes.js into comment.js.
After that, going into dishes.js,
let me cut this commentSchema completely out from here,
because we will be having this separately in the comments model here.
So, let's move that into the comments model and then paste it in here.
But of course this is not the complete one,
we're going to be updating the commentSchema a little bit.
But before we do that,
go back to dishes.js file and in the dishes file,
we will remove the comments from the dishesSchema,
because we're going to be storing the content separately from
the dishes in this version of our server.
So, that's how we will update the dishes model here.
So, we have removed the comments completely from the dishes model here.
Going into the comments model,
so we now see that we have the commentSchema implemented here.
But in addition, in the commentsSchema,
we now need to explicitly point to
the specific dish for which this comment is the corresponding comment.
Now, this is where
our mongoose population and
the way we store the object Ids comes to our rescue.
So, we will be updating the commentSchema saying we'll have the rating,
the comment, and author here.
In addition to the author,
we will introduce one more field called as the dish here which is of
the type: mongoose.Schema types.ObjectId,
and so this will refer to the Dish here.
So, this would be a object reference to the dish model here,
and so with this modification now
our comments will contain the rating field, the comment field,
the author which is again a reference to the corresponding user,
and then the dish field which is a reference to the corresponding dish here.
So, which means that we will now need to
populate the comments with both the author and the dish field.
Once we have completed this,
then we will say var Comments
mongoose.model and we will call this 'Comment',
and then this uses the commentSchema that we have just defined here,
and then we need to export this from here,
the comments.model from here.
So, now that we have introduced the comments.model,
then we will go ahead and then introduce a new Router called as the commentRouter.
So, to introduce the comment router,
let's go into the routes here,
and then create a new file named commentRouter.js.
In the commentRouter.js, let me copy a few things
over from the dishRouter.
So, we will have these comments here,
so let me copy over these things from the and also,
while I'm at it let me just copy these also up to that point,
and then I'll update that a little bit later.
So, going into the commentRouter,
we need all these parts,
so we'll say Com, Express, bodyParser, mongoose,
authenticate, cors, and then we will
be importing comments from models/comments.
Then we'll call this as the commentRouter which is an express.Router here.
Then we'll say commentRouter use bodyParser,
and then this would now become commentRouter route.
Now, we need to go into the dishRouter and then
remove all the parts that refers to the comments here.
So, let me just cut out this part and then we will reuse these for our commentRouter.
So, all these are no longer needed in the dishRouter.
So, I'm going to remove all this from the dishRouter here,
so let me cut them out,
everything related to the comments route from the dishRouter,
then we'll go into the commentRouter,
and then let me go ahead and paste that into place here,
then we will edit that here.
Then after this, we need to export the commentRouter.
So, will export the commentRouter for us.
But of course, this code is not completely accurate.
So, we need to go ahead and fix this code here.
So, for this code,
we now realize that this is not the dishRouter route,
instead that should be
the /endpoint because we're
going to be mounting this in the /comments endpoint here.
So, we'll say commentRouter,
and then the options corsWithOptions (req,
res) which remains as such there,
and then the get cors.cors and then req.res,
and then this one will become comments.
FindById, req.
So, this would be Comments.find
and req.query here.
So, when the comments is found,
then, at this point,
we will populate the author,
already have there, populate here.
So, I'm just going to remove this comments.author, and then,
we'll just simply populate the author here.
Then, this would give us comments here.
Then, we'll say, this can be simplified significantly.
So, the catch error is there anyway.
So, when the comment's coming, it'll simply return.
Sorry, that should be.
So, if for the get,
when we get the comments,
Comments.find req.query,.populate author here,
and then, we'll say,.then comments,
and then, we'll say, res.statusCode 200,
setHeader, and then, we'll return the comments from here,
res.json comments from here.
Now, I am not populating the dishes here because I don't explicitly need
the dishes the way I use this information in my react client.
I only need the dish ID,
and the dish ID is already present there,
and that is good enough for me to use this data in my react client.
So, I'm going to leave it as such there.
I'm only going to populate
the author information there because we need the full author information
whenever we render a comment item in our react client.
So, the get will be updated like this here.
For the post corsWithOptions,
we'll say, authenticate.verifyUser req, res, next.
Obviously, for a comment to be posted,
you need the author to be a valid logged in user.
Only then, you will allow the user to post a comment.
Then, the comment itself comes in the body of the incoming request message.
So, first, we'll check the body
to make sure that the comment is included in the body here.
So, here, I'm going to remove all these parts, and then,
simplify it further, and then,
we'll implement this correctly there.
So, right at this point, we'll say,
if req.body not equal to null,
so which means that there is a comment that is enclosed inside the body.
So, let me cut this and move this into the if part here,
and then, we'll edit that here.
So, if the body doesn't exist,
then we will cause an error.
So, we'll say, err new Error,
Comment not found in request body.
So, we'll raise this error here.
Error status is 404.
Then, we'll say, return next error.
So, let's handle the error part here if the body
doesn't contain the appropriate comment information.
If it contains, then, of course,
what we will do next is,
we'll say, req.body.author is req.user._id.
The reason why we're doing this is that we recall that if it
is a registered user and the user has logged in,
then the req.user will contain the user information.
So, I only need the ID of the currently logged in user.
So, we'll say, req.user._id, and then,
we'll set the req.body.author to req.user._id.
Now, the verify user will automatically ensure that if you land at this point,
then you would obviously have a user that has logged in correctly.
Otherwise, that would have already caused the problem there.
So, when you reach at this point,
you would have a valid user that has already logged in to the system in there.
So, this is where you would be able to now.
So, what we are doing is that the author field,
we are explicitly setting it into the user's ID here so that
the req.body contains the remaining parts of the comment.
So, as you realize, the comment contains the rating,
the comment itself, and the author, and the dish fields.
So, the remaining parts should have been filled by the user.
The rating, the comment,
and the dish information should already be filled
into the body of the incoming request message.
The author part is left unfilled there,
which we will explicitly insert at this point into the body here.
So, now, the req.body will contain the entire comment information.
So, at this point,
instead of doing this, we'll say, Comments.create.
Using the req.body, we'll create the comments here.
Then, this will return
the comment corresponding to the comment that we have just inserted here.
Now, once the comment has returned,
then we should do Comments.findById.
Now, the reason we need to do this is because we need
to populate the author information here.
So, we'll say, findById comments._id,
and then, we'll populate the author information into the comment itself.
Then, we'll say, then comment.
Now, obviously, here, you would find that the comment will
exist because we just inserted that comment into place there.
So, here, we will simply return, res.statusCode is 200,
res.setHeader is Content-Type, application/json.
The comment itself will say, res.json, and then,
return the comment at this point.
So, this is the way we will handle the insertion of
a new comment into our client side here.
For the put, as you realize,
you won't be able to do a put on the /comments/ end points.
So, we'll say, PUT operation not supported on /comments/ end point.
That's the point. That's the message that you'll return.
So, statusCode is 403,
and then, PUT operation not supported on /comments/.
Now, when we do a delete,
let me just cut this from here, and then, we'll say,
Comments.remove.
written empty. So, when you do a delete on the slash comments endpoint,
you will remove all the comments from your system.
So, this is a very dangerous operation, and so,
you should not be doing this normally.
So, we'll only allow the admin to perform such an operation.
So, we'll remove all the comments from there.
So, when you get the response,
then we'll say res.statusCode 200.
So, let me just copy these parts here,
and then come and paste it in here.
So, we'll say, comments.remove.
Then response res.statusCode 200 application json and then res.json(response) here.
So, that's how we handle the deletion.
Delete operation on the slash comments endpoint.
Now, the next route is the comment router.
So, here we'll say commentRouter.route and
the end point here would be the slash commentId.
So, here the options will remain as such.
Then for the get on the current router,
for the get we'll say, Comments.findbyID( req.params.
This would be commentId.
So, once we find the specific comment,
then we will populate just the author from there.
Then once you populate the author,
then we'll say, then comment.
Now, all this part is unnecessary here,
so I'm just going to delete the part.
This is also not the appropriate thing here.
So, let me rename code.
So, we'll say for the get Comments.findById,
then populate the author,
then comment, res.statusCode is 200, setHeader.
Then the rest are json.
We will be simply returning the comments here.
So, we'll be returning the comment at this point, res.json(comment).
You'll find the specific comment,
and then return that comment for the post.
For the post-operation, as you realize,
the post-operation is not
allowed on comments commentId.
So, that's the message that we'll send,
POST operation not supported on comments slash commentId.
So, that's the message we'll say for the put.
Now, for the put, we'll say Comments.find where Id(req.params.commentId).
So, we'll find the comment there,
and there comment, so for the put.
So, we'll find the comment there,
and then we'll say for the comments.
So, if we find the comment,
if the comment is not null,
then we'll also check if comment.author.
If not, comment.arthur equals(req.user._id).
So, we are cross-checking to make sure that
the comments.author is the same as the current user.
Only the current user who is logged in- if the user is the same as the comments author,
then the user will be allowed to update.
So, that's the first thing that we will check.
So, comments, then comments.author.equal to rec.user._id.
If not, then you will say you are not authorized to update this comment.
As you see the.403,
and then return next error here.
So, we'll create the error there.
Then after this, then we'll say
req.body.author, req.user._id.
That's important.
Now, these two are not necessary here,
because we are directly saving the comment.
Then pills, we'll say comments.findByIdAndUpdate,
and req.params.commentId.
So, we'll find that specific comment,
because we have already been supplied the comment ID.
So, we'll do comments findById req.params.commentId.
Then we'll say then(comment).
When you supply the req.params.commentId,
we'll have to explicitly supply the second parameter,
which is what we want to change.
So, we'll say $set: req.body.
So, the second parameter, essentially,
tells you which part you are changing.
Now, since we have been supplied the body containing the updated comment,
we're just going to update the entire comment itself.
Then the other part we'll ask for is new: true.
So, this will ensure that the updated comment will be returned in
the den of this call to the Comments.FindByIdAndUpdate.
So, we'll say then comments.
When that comment is returned,
then we'll say Comments.findById(comment._id).
Then populate the author there.
We'll populate the author there,
and then we'll say then comment.
So, you see that we'll obtain the comment and then return the comment at this point.
So, that's how we will be updating the comment.
So, this is the situation where the comment is not null.
So, this if statement for the comment is not null.
So, the else if part,
now this is not applicable,
so we'll say else, error.
The error in this case.
So, if the comment is null,
that means that we did not find the comment in there,
so you cannot modify a non-existent comment.
So we'll say err,
new Error comment req.params.commentId not found and then we'll return the error.
So, that's how we will handle the put part of our comment here,
and then finally the delete.
For the delete, again we'll have to first find
Comments.findById(req.params.commentId)
and then comment.
So, we'll look for the comment.
So, we'll first check if comment is not equal to null.
That's important to check here.
Then, the next part we will check for is if the comment.author equals req.user._id.
We make sure that this user that is trying to delete
this comment is exactly the same user that inserted the comment in the first place.
If not, so if this is the situation,
then you will see 'You are not authorized to delete this comment!'
And then return the status there.
Then down below here,
we'll say Comments.findByIdAndRemove here.
So, we'll say comments.findByIdAndRemove(req.params.commentId),
then we'll get some response from the comment.
So, at this point,
we'll simply say, res.statusCode.
So we'll say Comments.findByIdAndRemove then response.
If it is correctly removed,
we'll say 200 and then res.json
response here and we will also catch the error at this point.
So, let me just copy that here and then we'll include the catch of the err at this point.
So, that's the first thing that we'll check.
We'll ensure that the comment is not equal to null.
Otherwise, so this is the else part.
So, this is the else part of the if else error
new comment req.params.commentId not found and then
404 and send the else part for us and then the then part will handle appropriately.
So, this is the changes that we make for the comment router here.
So, we are handling the get put post and delete for
the slash comments and point slash comments slash commentId impact.
So once we have completed this,
then we need to include this into the app.js file.
So, we'll go into the app.js file and then we'll say
var commentRouter
require routes/commentRouter.
So, we have the comment router here and then we'll go
down into the app.js file down below here and
then we will say app.use
slash comments, commentRouter here.
That's it. So now,
my comment router is ready.
So, let's go ahead and save all the changes.
Then our server is now updated in
order to handle all the requests from our React clients here.
Now, if you want to do the alternative way, that is,
you have your comments as sub-documents of your dish and then you want to handle that,
then you will need to update the React client to be able
to use the comments from within each dish appropriately.
That will be left as an exercise for you.
Think about how you would design your react client such that it
works very well with the earlier version of
the server which had the comments as sub-documents of your dishes themselves.
Now, that'll be an interesting way of implementing it.
Of course, it's a bit more complicated than the way we
implemented the React client where we kept the comments independent of
the dishes but then the additional work is then the responsibility
of the client side because you need to select
the appropriate comments when you're showing a specific dish.
You need to select the comments from all the comments here.
So, that's one additional work that our React client does because of
the fact that we separated the comments from the dishes themselves.
Similarly, if you can redesign your angular client to be able to
deal with the situation where the comments are kept independent of your dishes.
Now, so these are all exercises that you can do in order to see how you can
extend your client applications to handle any kind of server,
the two different kinds of servers there.
So, with this, we complete the update to our server here.
So, with this, we have updated everything on the server side.
So, let's save all the changes on the server side.
So now, our server is all ready to handle the incoming requests from our React client.
With this, we complete this exercise.
In this exercise, we have now prepared our express server
to handle incoming requests from our React client.
In the next exercise, we're going to look at react client in more detail to
understand how it is communicating with this extra server.
This is a good time for you to do
a git coverage with the message integrating client and server.