Genius level series. I love how you show default return data from the API and then how you make it more relevant to the function that the particular method is performing. It is also very enlightening when there is a particular error, such as the exec() on the post for orders, that you explain why that happened. Glad this series popped up on my radar. I appreciate your hard work and teaching!
I really like the way you teach. You always explain why "what is what". Your smiles are beautiful as well. But they can also be annoying when I'm not getting something right :)
Happy to read that you like my videos! I definitely try to keep that happy attitude, because although coding can be tough, we should enjoy what we do whenever possible :)
If this could have just came 2 months back....you could have saved me a infinite amount of hard work I needed to do to find all these and still can't find with this crystal clear explanation. God is not in heaven.. He is on Earth and I can see that.. Today is 31 dec and I find it so interesting that on the occasion of new year all I am going to do is watch these tutorials because this is too much fun.
Max, still very spot on. Like the way you guys work at academind. Very good way to start this old dog learning new things after years of not programming at all. Clear tutorial. Thx.
Your videos are amazing, as I'm sure you know! I love how to take the time to explain everything, even if it may be very basic concepts because it helps us learn how much better. I love how you branched the git for this tutorial series, it makes it so much easier to follow along and see where I went wrong. Thanks again Max!
16:49: I think there is a bug here. I've just tested and seen that even if "return" is used, the code WOULD NOT stop executing there, which means the 2nd then() block will still be run no matter what the result of the "Product.findById" is. It's because there is no exception triggered in the first then() block (just the doc is not found) so the code will keep going down to the next then() instead of exiting. So when the 2nd then() block is run, the response would be sent again by this code "res.status(201).json(...)" and as a result "cannot set headers after they are sent to the client" exception will be thrown.
try this code, with an if statement to validate for the product's existence, while also returning an 404 error for Product not found. The return statement inside the first .then statement will prevent the second .then statement from running. code below: Product.findById(req.body.productId) .then(product => { if (!product) { return res.status(404).json({ message: "Product not found in Database...", error: err }) } const order = new Order({ _id: new mongoose.Types.ObjectId(), quantity: req.body.quantity, product: req.body.productId }) return order.save() }) .then(result => { console.log(result) res.status(201).json({ message: "Order created successfully!", createdOrder: { _id: result._id, product: result.product, quantity: result.quantity }, request: { type: 'GET', description: "Get Info on the Newly Created Order!", url: '/orders/' + result._id } }) }) .catch(err => { res.status(500).json({ message: "Order could not be stored correctly...", error: err }) })
Thanks Max ...Your way of explaining the things is quite crystal clear...And by the way this series of yours is 100 times better than some Moocs I took months ago...because you make it so easy to grasp even slightest of the things and we come to know about the latest coding conventions from you.( I use to work with async await but even promises is quite good to work with)
It really means a lot to me to read that Prateek, thank you very much! So happy to see that my way of explaining helped to make things clearer for you :)
Hi there, I get an error when trying to POST an order Here is the error { “error”: { “ message “ : “ Class constructor ObjectId cannot be invoked without ‘ new ‘ “ } }
I also got the error and just added 'new' in the _id: new mongoose.Types.ObjectId(), const order = new Order({ _id: new mongoose.Types.ObjectId(), product: req.body.productId, quantity: req.body.quantity });
Thank you Max for your videos. Atm going through your Vue course. If its possible in future would like to see a Vue+(express maybe?)+mongo or sql project. Cheers
Thank a ton Max, i always follow your series of node.js and other tutorials as well. You really make it a piece of cake :) Please make a video on "how to scale node.js application" to make it faster and lightweight. Thanks!
For everyone facing UnhandledPromiseRejectionWarning while doing POST request with incorrect productId, maybe this will help: in second "then" , try to add this code at the beginning: if(res.statusCode===404){ return res; } Now warning disappear and we have a right error code. I hope it helped?
for any future watchers, if you're getting the error "product: ValidatorError: Path `product` is required." at around 8:00 when attempting to create the order, make sure you're setting the content-type in postman to JSON.
As far as I know: In your model use[{ref to products }] => indicates that you are expecting one or more products as reference. In your route: Check if input (req.body) is an array, if not convert it to one by using New Array(req.body). Then just add that to your model order = new product({ ... products = Array(req.body) })
Yes, but I would recommend an array of product objects. NoSQL DBs are supposed to be used like that: To store objects, not link everything with IDs. If you want to use ID to link everything, it is better to use a SQL DB.
Shouldn't you add a findById check when deleting an order? If you send a DELETE request for an invalid orderID you get back a response with "Order deleted", but that ID never existed.
It might be a bug in my code, but I was getting the "Cast to ObjectId failed" error in the POST router in "orders.js" whenever I entered an incorrect productId. I worked around the issue by wrapping the Product.findById().then().then().catch() code in an if-else statement: if(mongoose.Types.ObjectId.isValid(req.body.productId)) { Max's code here (no need to check for !product) } else { console.log("invalid product id"); return res.status(500).json({ message: "invalid product id" }); }
@@geTTh1s Yes, you are correct. It's been a while since I worked on this project but I suspect I added the 500 response so I could handle the error gracefully on the client end instead of having the request just fail without letting the user know the reason...
@@galwayiilt i mean the key word "return" specifically though. We get the same result when we leave that little word out right, only writing res.status(500)...
i keep getting this error at 8:00, and i havent a clue how to solve it, can anyone help Error: Order validation failed: product: Path `product` is required.
User is already required, so the following throws an error user: { type: mongoose.Schema.ObjectId, ref: 'User', required: true } Change to user: { type: mongoose.Schema.ObjectId, ref: 'User' }
Perhaps this may help from what I understand. 3 differnt cases below without all the excess code for simplicity. //case1: router.get("/", (req, res, next) => { Order.find() .select("product quantity _id") //.exec() //***Without exec( ) would not be able to write a catch block below .then(docs => { }); }) // .catch(err => { //***CANT use catch block here since no exec( ) // res.status(500).json({ // error: err // }); // }); }); //case2: router.get("/", (req, res, next) => { Order.find() .select("product quantity _id") .exec() //***with exec( ) , we now have a REAL promise so can use thecatch block as follows .then(docs => { }); }) .catch(err => { //***CANT use catch block here since no exec( ) res.status(500).json({ error: err }); }); }); //case3: router.post("/", (req, res, next) => { Product.findById(req.body.productId) return order.save(); }) //***Here we do not need exec because with save( ) (executed above)you get a REAL promise by default so no need for exec( ) .then(result => { }) .catch(err => { }); });
However, I am able to execute the code inside the catch blocks where we catch any 500 status errors without exec( ). So now I don't see any use of exec( ) at least based on how Max justified its usage.
When entering invalid productId that doesn't exist in products, has anyone observed that some ids return `Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters`?
i keep getting this error when hitting the "/orders/" "POST" endpoint, when placing a new order with invalid product id: UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after theyare sent to the client. did anyone face the same error?! i get it why i'm getting this error but how could i resolve it ?!
i could manage to workaround the error by refactoring the "/orders/" "POST" endpoint like this: router.post("/", (req, res, next) => { Product.findById(req.body.productId) .then(product => { if (!product) { return res.status(404).json({ message: "Product not found" }); } const order = new Order({ _id: mongoose.Types.ObjectId(), quantity: req.body.quantity, product: req.body.productId, }); order.save().then(doc => {
i gave it another try and did this: router.delete('/delete/:orderId', (req, res, next) => { const id = req.params.orderId; Order.findById(id) .exec() .then(order => { if (!order) { return res.status(200).json({
Hey, really enjoying your videos but one thing is bugging me. Why do you explicitly set the Mongo ID? It automatically creates one for you. Why do the work?
Actually only to highlight that this id is an important part (as we then use it to fetch elements by it). Should've made that more clearer though, you are right
The orders.js generates new orders everytime you add the same /:productid and send a post request to the /orders even though the same product is already in the orders list, instead how do we manipulate that, to just add the quantity of that particular product everytime the same product is posted to the /orders
At order.js router.get() why did you create .map() method ? We can get that _id by result._id also. You used .map on get and not in post. Would you care to explain this please.
i don't think it will work...you need to validate orderlist and check every time that product you are adding is exit in your orderlist or not.@Narasimha Kamath
In Mongoose queries are composed but not necessarily run immediately. They return a query object that you can add (or chain) other queries to. The queries are all run as a unit when needed so there isn't any storing of unneeded intermediate results. This is what the exec() function does. You'll sometime hear it referred to as "lazy loading" or "lazy evaluation" teamtreehouse.com/community/what-exactly-does-the-mongoose-exec-method-do
I reviewed this reference model three or four times, and only now begin to understand it) I think that's okay. Also, I think it's difficult, because mongodb uses another model called "Embedded documents" more often, which in my opinion is easier
I don't understand why at 15:09 we write return order.save(). Why do we need 'return' keyword? What happens when we return a promise? Do we still hit exception handling if it goes wrong?
@@geTTh1s It's been a while. 😀 I think the "return" simplifies the creation of a promise in the scope of innermost curly brackets, other promises in that chain execute as before.
Hello. In orders.js when I try to save order with productId that does not exist I get error: UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
I figured out how to make it work correctly. In router.post() insted of if (!product) { return res.status(404).json({ message: "Product not found" }); } I wrote : if (!product) { throw "Product not found"; }
I get the same error and I think there is something wrong with chaining promise like that. When (!product) is true (productId does not exist) we are returning res.status(404).json(..) to the next then() block where there is another response: res.status(201).json(..). Your solution with changing return to throw is indeed working but it's not giving the same result. We are getting status 500 from the last catch block instead of just 404 from the first if statement.
I ran into this too, and rewrote the route handlers using async/await. Allows you to return the response as originally intended. router.post('/', async (req, res, next) => { try { let product = await Product.findById(req.body.productId).exec(); if (!product) { return res.status(404).json({ message: "Product not found" }); } const order = new Order({ _id: mongoose.Types.ObjectId(), quantity: req.body.quantity, product: req.body.productId }); let result = await order.save(); res.status(201).json({ message: 'Order saved', createdOrder: { _id: result._id, product: result.product, quantity: result.quantity }, request: { type: 'GET', url: 'localhost:5000/orders/' + result._id } }); } catch (err) { res.status(500).json({error: err.message}); } });
Correct! Faced the same problem. What I did is added a check in the secnd .then() to first check if the result.statusCode !== 404. If it's not 404 then only proceed to return response 201 along with created order data.
Is this a bug? in the POST route, there are 2 then promise after Product.findById(req.body.product_id): the first promise returns "Product not found" and the second promise is executed too. check this out: // ===== Test ===== const promise1 = new Promise((resolve, reject) => { resolve('Success!'); });
promise1.then((value) => { console.log("==== then 1 ====") return 0 }) .then(value => { console.log("==== then 2 ====") }); // _____ Test _____ // ====== output ===== ==== then 1 ==== ==== then 2 ====
Nein - generell behandelt diese API nicht alle möglichen Kombinationen sondern lieber möglichst viele unterschiedliche Aspekte (bspw. verschiede HTTP Verben, Auth (kommt noch) etc).
if (!product) { return res.status(404).json({ message: 'Product Not Found' }); } The above code does not execute inside the orders.js file when you enter an invalid productId .Instead the .catch block executes where the code block sends a json(500). Anyone have a fix for this? Thanks in advance
Anyone gets the same result as mine with .delete() method? If I try to delete the order that was already deleted, I get the result with "DeleteCount: 0". Mongoose kind of putting deleted item in the cache or something. So it remembers the deleted items. So if I delete the order with the same id multiple time, it doesn't show "invalid id". Also, in there is message in the console telling me that .remove is deprecated and suggest that .deleteOne, .deleteMany, and .bulkwrite should be used instead.
Hello! Does anyone know how can I solve the error : "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" when I get products by their ID? Thanks a lot!
16:44 this won't work, you will return the response to the next chain, which will try to set the header once more and throw an error, doing an if(promise){ } else { } branching instead and chaining the remaining execution that branches from a found product id onto the save() promise and letting the 404 close up the POST request instead solves this problem
In post man it is showing json "product not found" thing. But in the console I am getting a huge error. which is lines and lines of code that I can't paste here. Here's the look of it at the end. Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:526:11) at ServerResponse.header (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:771:10) at ServerResponse.send (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:170:12) at ServerResponse.json (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:267:15) at E:\WebP\JSPractice odePractice estful-academind\api outes\orders.js:27:29 at processTicksAndRejections (internal/process/task_queues.js:97:5) { code: 'ERR_HTTP_HEADERS_SENT' } POST /orders 500 770.054 ms - 31 (node:24860) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:526:11) at ServerResponse.header (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:771:10) at ServerResponse.send (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:170:12) at ServerResponse.json (E:\WebP\JSPractice odePractice estful-academind ode_modules\express\lib esponse.js:267:15) at E:\WebP\JSPractice odePractice estful-academind\api outes\orders.js:42:29 at processTicksAndRejections (internal/process/task_queues.js:97:5) (node:24860) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:24860) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
@@hemanthvarmas The error printout you're getting seems large because its a stack trace, a lot of it coming from the express library source code. The most important part of the error, which will give you a clue about why the exception is being thrown is this: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client, and the line it refers to at the bottom of the stack trace here: E:\WebP\JSPractice odePractice estful-academind\api outes\orders.js:42:29. This error is node trying to tell you that you are trying to set something in the response header twice, likely this is happening because you are setting a code in the header up in the method, and then trying to reset it on a separate conditional branch after it has been returned.
The second error you're getting is trying to tell you that you are letting an exception thrown inside a promise go unhandled, you can check the promise that the stack trace is pointing at and see if you're missing a catch block for it. The exception that is being thrown and going unhandled is most likely the error above where you are trying to set a field in a header multiple times after returning it.
Because you want to protect those from being re-declared. You can assign new values of course, but you wouldn't ever want to expose it globally and allow it to be a new data type or data structure. Var is deprecated and should really not be used. Rule of thumb, start with const until you have to use let, do not use var.
For the error: UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. Try with async-await: router.post('/', async (req, res, next) => { try { const productFound = await Product.findById(req.body.productId).exec(); if (!productFound) { return res.status(404).json({ message: "product not found" }) } const creatredProduct = new Product({ // ... }); const documentCreated = await creatredProduct.save(); console.log('Create document', documentCreated); const response = { message: 'Created asset successfully', // ... }; res.status(201).json(response); } catch (err) { res.status(500).json({error: err.message}); } }); As displayed on the console, the error description is: UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
at 15:45 I have a question (I'm super noob) Why do I need 2 promises. Or in other words, why do I need to .then() blocks. Can't I just store the order, the response, and the metadata, all in the same .then() block? I promise you, I'm not trying to be a wise guy. I really do want to know, because I'm not very good at this. If someone takes the time to respond, I'll be grateful :)
using Product.find() .exec() ....... gives me this error in postman = Product.find(...).exec(...).select is not a function" I don't really know what's the reason. if I remove exec it works. does Anyone know which kind of problem I'm facing?
Hello Max, love your videos, but in this tutorial I got stuck after implementing the router.post('/', ....), whenever I try to POST the order in postman software it comes out as { "error": { "message": "document must have an _id before saving", "name": "MongooseError" } } and nothing gets posted in localhost:3000/orders I mean why does the mongoose expect the `_id` to be there first, isn't the productId should suffice for that? I"m sorry if I'm vague , provide any explanation or suggestion that will help me guide
That was required because he wanted to add more information to each record in the orders array, so he needs to loop through each order using the "map" and then adding the request element. This is not needed if you simply return the raw array.
Hi, Max. It is very hard to follow your fast scrolling at 15-16 minutes. Had to re-watch and re-play several times till I get it. Just a reminder to slow it down other time. Otherwise, great content!
Sorry for the confusion: I was not referring to different kinds of promises, just of different ways of getting them (directly chaining then()/catch() vs the need to use exec() first).
Is it? When we set Mongoose.Promise = global.Promise I assume Mongoose starts using global promise object, after all, if queries actually allow .then() as well as .catch() to be chained onto them what situation can actually require using .exec() in favor of not using it?
you can create same video mysql node js express same product(add,delete,edit,list),order(add,delete,edit,list), validation , join to table order and product and login ,registration authtoken routers all 14 video please created
Its kinda weird, when I pass req.params.orderId directly in Order.findById(), it cannot get the order details but when I assign the req.params.orderId value in id variable it works.. can someone tell me why?
By me POST with wrong product id doesn't work even without this check: if(!product) { return res.status(404).json({ message: 'Product not found' }); } I get this: { "message": "Product not found", "error": { "message": "Cast to ObjectId failed for value \"5a747be38f17ec1ea8255fd21\" at path \"_id\" for model \"Product\"", "name": "CastError", "stringValue": "\"5a747be38f17ec1ea8255fd21\"", "kind": "ObjectId", "value": "5a747be38f17ec1ea8255fd21", "path": "_id" } } What's the reason?
Hello, did you find a solution yet? I get an error when trying to POST an order Here is the error { “error”: { “ message “ : “ Class constructor ObjectId cannot be invoked without ‘ new ‘ “ } }
th-cam.com/video/VKuY8QscZwY/w-d-xo.html I don't know how to get the time-link in the comment so I copied the link at that duration. Please check the above link which should take you at 16:47 of the video. In that, you've put an IF condition thinking that if it passes, it won't go into the next then() method. But, it does. You do get the response as you've expected but try checking your console or put console.log() in the next then() method. You'll see it does go into that irrespective of the condition you've put. If you find it, please fix it with a good approach. I've done it somehow but I don't think I've made it the way it should be.
Sorry Luca, always hard to find the right balance between too fast and too slow. Did you try to change the playback speed in the TH-cam player? Maybe this helps a bit here.
I think it's difficult to follow because it doesn't show what shortcuts he's pressing. Also what he selected isn't what most people would think he is copying. So here's the breakdown, where the problem starts to happen for a lot of folks. If you go to your code before he starts moving anything before 15:00. You should've just typed inside .then() product => { ... and left it blank take everything after the first catch block and post it inside of the first .then(product => { ... }) then delete the catch(err => .. block because it will be redundant to the one you've just written for the .then(result => { .. order stored }
Genius level series. I love how you show default return data from the API and then how you make it more relevant to the function that the particular method is performing. It is also very enlightening when there is a particular error, such as the exec() on the post for orders, that you explain why that happened. Glad this series popped up on my radar. I appreciate your hard work and teaching!
Thank you Haakon, feedback like yours definitely keeps me motivated :)
I really like the way you teach. You always explain why "what is what".
Your smiles are beautiful as well. But they can also be annoying when I'm not getting something right :)
Happy to read that you like my videos! I definitely try to keep that happy attitude, because although coding can be tough, we should enjoy what we do whenever possible :)
calm, composed and very patient.
Best teacher!
Thank you very much for your awesome feedback, it really means a lot to me to read that!
If this could have just came 2 months back....you could have saved me a infinite amount of hard work I needed to do to find all these and still can't find with this crystal clear explanation. God is not in heaven.. He is on Earth and I can see that.. Today is 31 dec and I find it so interesting that on the occasion of new year all I am going to do is watch these tutorials because this is too much fun.
Awesome to hear that, thank you so much!
Max, still very spot on. Like the way you guys work at academind. Very good way to start this old dog learning new things after years of not programming at all. Clear tutorial. Thx.
Your videos are amazing, as I'm sure you know! I love how to take the time to explain everything, even if it may be very basic concepts because it helps us learn how much better.
I love how you branched the git for this tutorial series, it makes it so much easier to follow along and see where I went wrong. Thanks again Max!
Thank you very very much for your wonderful feedback Benji, just great to read that you enjoy the series :)
16:49: I think there is a bug here. I've just tested and seen that even if "return" is used, the code WOULD NOT stop executing there, which means the 2nd then() block will still be run no matter what the result of the "Product.findById" is.
It's because there is no exception triggered in the first then() block (just the doc is not found) so the code will keep going down to the next then() instead of exiting.
So when the 2nd then() block is run, the response would be sent again by this code "res.status(201).json(...)" and as a result "cannot set headers after they are sent to the client" exception will be thrown.
@Aditya Jaiman same. time to quit the series I guess
Use res.statusCode to check if the status code was already set before setting it again in the new then/catch block. If it was set, then just return;
try this code, with an if statement to validate for the product's existence, while also returning an 404 error for Product not found. The return statement inside the first .then statement will prevent the second .then statement from running.
code below:
Product.findById(req.body.productId)
.then(product => {
if (!product) {
return res.status(404).json({
message: "Product not found in Database...",
error: err
})
}
const order = new Order({
_id: new mongoose.Types.ObjectId(),
quantity: req.body.quantity,
product: req.body.productId
})
return order.save()
})
.then(result => {
console.log(result)
res.status(201).json({
message: "Order created successfully!",
createdOrder: {
_id: result._id,
product: result.product,
quantity: result.quantity
},
request: {
type: 'GET',
description: "Get Info on the Newly Created Order!",
url: '/orders/' + result._id
}
})
})
.catch(err => {
res.status(500).json({
message: "Order could not be stored correctly...",
error: err
})
})
Your videos are really nice, this is how we learners expect to be explained.
Thanks Max ...Your way of explaining the things is quite crystal clear...And by the way this series of yours is 100 times better than some Moocs I took months ago...because you make it so easy to grasp even slightest of the things and we come to know about the latest coding conventions from you.( I use to work with async await but even promises is quite good to work with)
It really means a lot to me to read that Prateek, thank you very much! So happy to see that my way of explaining helped to make things clearer for you :)
You are so nice in teaching, and also "serious" in the series. 😅
Haha, thanks a lot!
Hey Max just wanna say thank you so much for this free content! Its been making things crystal clear.
Thanks for your awesome feedback - really great to hear this! :)
Hi there,
I get an error when trying to POST an order
Here is the error
{
“error”: {
“ message “ : “ Class constructor ObjectId cannot be invoked without ‘ new ‘ “
}
}
I also got the error and just added 'new' in the _id: new mongoose.Types.ObjectId(),
const order = new Order({
_id: new mongoose.Types.ObjectId(),
product: req.body.productId,
quantity: req.body.quantity
});
This guy is a legend.
For the post request to work, you need to set new in _id: new mongoose.Types.ObjectId() and also delete exec()
Thank you Max for your videos. Atm going through your Vue course. If its possible in future would like to see a Vue+(express maybe?)+mongo or sql project. Cheers
Thank you very much for this course. You are by far the best teacher I had and trust me I had many before.
Thank you so much for your awesome feedback Charl, this really means a lot to me :)
Thank a ton Max, i always follow your series of node.js and other tutorials as well. You really make it a piece of cake :)
Please make a video on "how to scale node.js application" to make it faster and lightweight.
Thanks!
Thanks for your very nice feedback Faisal - and of course for the suggestion. I'll see what I can do ;)
Excellent tutorial, but the fast copying and pasting made it a bit fuzzy. it took me a few rewinds to catch up. Thank goodness for the source code!
For everyone facing UnhandledPromiseRejectionWarning while doing POST request with incorrect productId, maybe this will help:
in second "then" , try to add this code at the beginning:
if(res.statusCode===404){
return res;
}
Now warning disappear and we have a right error code. I hope it helped?
Thanks buddy this helped..
Why does it reach this point even after returning? Thanks anyway.
thanks bro!
hi karol, it works,thanks . can you please explain why its not reach the catch ?
Dude!!! I'm stuck on this for almost 1 hour!!! I love You!!!
for any future watchers, if you're getting the error "product: ValidatorError: Path `product` is required." at around 8:00 when attempting to create the order, make sure you're setting the content-type in postman to JSON.
How would I add multiple products to ONE order?? make it an array and push product IDs?
@Narasimha Kamath by creating another model named 'OrderItem" having fields like 'productid', 'quantity'.
same question here!
Have we gotten an answer to this question??
you can use insertMany method
As far as I know:
In your model use[{ref to products }] => indicates that you are expecting one or more products as reference.
In your route:
Check if input (req.body) is an array, if not convert it to one by using New Array(req.body).
Then just add that to your model
order = new product({
...
products = Array(req.body)
})
Thank you for such wonderful contents for free!
How would you create an order model that could have multiple products? An array of product IDs?
Yes, but I would recommend an array of product objects. NoSQL DBs are supposed to be used like that: To store objects, not link everything with IDs. If you want to use ID to link everything, it is better to use a SQL DB.
I would suggest using the .serialize() method to avoid having to retype all of those response objects.
nice tutorial, i liked the way of teaching
That's really great to read, thank you for your comment!
Great lectures buddy 👍🏻
6:06 - Anybody know what keyboard shortcut automatically formats the code in that fashion?
Just look for "Format Document" in the Keyboard Shortcuts of VS Code :)
look up an npm package called prettier. Thats a tools that will formats your code for you. its very minor set up too. www.npmjs.com/package/prettier
You're the best teacher!! Thanks.
Thank you so much, this really means a lot to me :)
Most helpful tutorial, maybe ever. Thank you really damn much!
Just awesome to read that Sarah, thank YOU for this fantastic feedback!
I think use async/await along with try/catch would be better in configuring route
19:13 nice segue mate!
Thank you :)
Tell me please, how to beautify promise chain after save? (what setting is set?)
Shouldn't you add a findById check when deleting an order? If you send a DELETE request for an invalid orderID you get back a response with "Order deleted", but that ID never existed.
It might be a bug in my code, but I was getting the "Cast to ObjectId failed" error in the POST router in "orders.js" whenever I entered an incorrect productId. I worked around the issue by wrapping the Product.findById().then().then().catch() code in an if-else statement:
if(mongoose.Types.ObjectId.isValid(req.body.productId)) {
Max's code here (no need to check for !product)
}
else {
console.log("invalid product id");
return res.status(500).json({
message: "invalid product id"
});
}
Thanks for the solution. I had exactly same problem.
what does the return in your else case do? we get the same result without a return before "res.status...." dont we?
@@geTTh1s Yes, you are correct. It's been a while since I worked on this project but I suspect I added the 500 response so I could handle the error gracefully on the client end instead of having the request just fail without letting the user know the reason...
@@galwayiilt i mean the key word "return" specifically though. We get the same result when we leave that little word out right, only writing res.status(500)...
Awesome video!
How do I alter the post to grab/hold multiple products? @Academind
i keep getting this error at 8:00, and i havent a clue how to solve it, can anyone help
Error: Order validation failed: product: Path `product` is required.
Error: Order validation failed: product: Path `product` is required.
User is already required, so the following throws an error
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
}
Change to
user: {
type: mongoose.Schema.ObjectId,
ref: 'User'
}
I want to ask that in order schema if i want to add the user detail(like the users id,name,address,phone,email) what i need to do?
in 2024 but its still awesome waiting for Express , mongoDB
Thank u for this awesome video
Thanks again for your great support Abhishek :)
Why does he write 'POST' in 'DELETE' method??
How you change your code verticaly?
how sir changed all occurence at.048
Can someone please elaborate the use of exec()
Where to use exec() and where not.
I am quite confused with that.
Thanks in advance :)
Perhaps this may help from what I understand. 3 differnt cases below without all the excess code for simplicity.
//case1:
router.get("/", (req, res, next) => {
Order.find()
.select("product quantity _id")
//.exec() //***Without exec( ) would not be able to write a catch block below
.then(docs => {
});
})
// .catch(err => { //***CANT use catch block here since no exec( )
// res.status(500).json({
// error: err
// });
// });
});
//case2:
router.get("/", (req, res, next) => {
Order.find()
.select("product quantity _id")
.exec() //***with exec( ) , we now have a REAL promise so can use thecatch block as follows
.then(docs => {
});
})
.catch(err => { //***CANT use catch block here since no exec( )
res.status(500).json({
error: err
});
});
});
//case3:
router.post("/", (req, res, next) => {
Product.findById(req.body.productId)
return order.save();
})
//***Here we do not need exec because with save( ) (executed above)you get a REAL promise by default so no need for exec( )
.then(result => {
})
.catch(err => {
});
});
However, I am able to execute the code inside the catch blocks where we catch any 500 status errors without exec( ). So now I don't see any use of exec( ) at least based on how Max justified its usage.
what is the Builder utility you are using @7:30
You're the best man
YOU are the best Victor, thank you for your support!
Hye What is keyboard shortcut for aligning order.save().exec().then().catch();
does not work for me, I would like to know this trick
vs extension called Prettier github.com/prettier/prettier-vscode
Alt + Shift + F
thank you teacher for share education for everyone
If I wanted to update de price everytime I POST an order. How would I be able to do that?
Is there a form to also display the name of the product and the price on the body?
How to consume these api from node js ejs pages
if we want to link any other field like name or roll_no then what do we edit in the code?
When entering invalid productId that doesn't exist in products, has anyone observed that some ids return `Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters`?
14:15 Forgot an exec() ?
create an REST API using Node.js having tweeter like functionalities:
● Authentication / Login
● Create / Read / Delete tweets
● Reply to a tweet
== I need help in creating schema
required: true is not working for me, it is accepting the orders with no properties being provided in the req body. Please help !!
Can I use .findOneById inside a .then promise ?
i keep getting this error when hitting the "/orders/" "POST" endpoint, when placing a new order with invalid product id:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after theyare sent to the client.
did anyone face the same error?!
i get it why i'm getting this error but how could i resolve it ?!
i could manage to workaround the error by refactoring the "/orders/" "POST" endpoint like this:
router.post("/", (req, res, next) => {
Product.findById(req.body.productId)
.then(product => {
if (!product) {
return res.status(404).json({
message: "Product not found"
});
}
const order = new Order({
_id: mongoose.Types.ObjectId(),
quantity: req.body.quantity,
product: req.body.productId,
});
order.save().then(doc => {
i gave it another try and did this:
router.delete('/delete/:orderId', (req, res, next) => {
const id = req.params.orderId;
Order.findById(id)
.exec()
.then(order => {
if (!order) {
return res.status(200).json({
another approach :
router.delete('/delete/:orderId', (req, res, next) => {
const id = req.params.orderId;
Order.findById(id)
.exec()
.then(order => {
if (!order) {
res.status(200).json({
message: 'order does not exist'
});
return;
Hey, really enjoying your videos but one thing is bugging me. Why do you explicitly set the Mongo ID? It automatically creates one for you. Why do the work?
Actually only to highlight that this id is an important part (as we then use it to fetch elements by it). Should've made that more clearer though, you are right
The orders.js generates new orders everytime you add the same /:productid and send a post request to the /orders even though the same product is already in the orders list, instead how do we manipulate that, to just add the quantity of that particular product everytime the same product is posted to the /orders
At order.js router.get() why did you create .map() method ? We can get that _id by result._id also. You used .map on get and not in post. Would you care to explain this please.
try to add one product twice and observe that just quantity of that should be increased and not add the duplicate entry in the database.
i don't think it will work...you need to validate orderlist and check every time that product you are adding is exit in your orderlist or not.@Narasimha Kamath
Could somebody explain why we are using exec()???
In Mongoose queries are composed but not necessarily run immediately. They return a query object that you can add (or chain) other queries to. The queries are all run as a unit when needed so there isn't any storing of unneeded intermediate results. This is what the exec() function does. You'll sometime hear it referred to as "lazy loading" or "lazy evaluation"
teamtreehouse.com/community/what-exactly-does-the-mongoose-exec-method-do
@@oussamakhalfi1751 Thank you!
Error: Order validation failed: product: Path `product` is required.
At 16:55 an UnhandledPromiseRejectionWarning is generated. >> Cannot set headers after they are sent to the client
I am lost after 15:00
x2
I reviewed this reference model three or four times, and only now begin to understand it) I think that's okay.
Also, I think it's difficult, because mongodb uses another model called "Embedded documents" more often, which in my opinion is easier
I need serious help here. If i add the : if(!product){ return res.status...
Valid products id return an error too :(
i know i am 1 year late to reply, but answer is
first see his callback,promises and async await video then you will not get lost from 15:00
Hi!! How would i search for an order by the _id of a product?
can anyone help me with this "Cannot read property 'ObjectId' of undefined"
I don't understand why at 15:09 we write return order.save(). Why do we need 'return' keyword? What happens when we return a promise? Do we still hit exception handling if it goes wrong?
Hey you found the answer to your question? I'm wondering the same
@@geTTh1s It's been a while. 😀 I think the "return" simplifies the creation of a promise in the scope of innermost curly brackets, other promises in that chain execute as before.
@@s_k12 not sure if I get what you mean but thanks anyway haha. The return doesn't change the outcome though as I tried it with and without
You can avoid this error - Error [ERR_HTTP_HEADERS_SENT]: - by replacing the return statement with: throw 'Product not found';
But what causes the error?
Hello. In orders.js when I try to save order with productId that does not exist I get error: UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
I figured out how to make it work correctly. In router.post() insted of
if (!product) {
return res.status(404).json({
message: "Product not found"
});
}
I wrote :
if (!product) {
throw "Product not found";
}
I get the same error and I think there is something wrong with chaining promise like that. When (!product) is true (productId does not exist) we are returning res.status(404).json(..) to the next then() block where there is another response: res.status(201).json(..). Your solution with changing return to throw is indeed working but it's not giving the same result. We are getting status 500 from the last catch block instead of just 404 from the first if statement.
router.post('/', (req, res, next) => {
//ürün id geçerli mi?
Product
.findById(req.body.productId).exec()
.then(product => {
if (!product) {//bulunamayınca null geliyor
res.status(404).json({
message: 'Ürün Bulunamadı ' + req.body.productId,
})
} else {
const order = new Order({
_id: new mongoose.Types.ObjectId(),
product: req.body.productId,
quantity: req.body.quantity,
});
order.save()
.then(result => {
console.log(result);
res.status(201).json({
message: 'Sipariş Kaydedildi',
createdOrder: {
id: result._id,
product: result.product,
quantity: result.quantity,
request: {
type: req.method,
url: req.protocol + '://' + req.headers.host + req.url + 'orders/' + result._id
}
}
})
})
.catch(err=>{
console.log(err);
res.status(500).json({
error: err
})
})
}
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
});
});
I ran into this too, and rewrote the route handlers using async/await. Allows you to return the response as originally intended.
router.post('/', async (req, res, next) => {
try {
let product = await Product.findById(req.body.productId).exec();
if (!product) {
return res.status(404).json({
message: "Product not found"
});
}
const order = new Order({
_id: mongoose.Types.ObjectId(),
quantity: req.body.quantity,
product: req.body.productId
});
let result = await order.save();
res.status(201).json({
message: 'Order saved',
createdOrder: {
_id: result._id,
product: result.product,
quantity: result.quantity
},
request: {
type: 'GET',
url: 'localhost:5000/orders/' + result._id
}
});
} catch (err) {
res.status(500).json({error: err.message});
}
});
Correct! Faced the same problem. What I did is added a check in the secnd .then() to first check if the result.statusCode !== 404. If it's not 404 then only proceed to return response 201 along with created order data.
Hey hi!! Can u help me by providing the tutorial that how can u relate more then 2 table..
Is this a bug?
in the POST route, there are 2 then promise after Product.findById(req.body.product_id):
the first promise returns "Product not found" and the second promise is executed too.
check this out:
// ===== Test =====
const promise1 = new Promise((resolve, reject) => {
resolve('Success!');
});
promise1.then((value) => {
console.log("==== then 1 ====")
return 0
})
.then(value => {
console.log("==== then 2 ====")
});
// _____ Test _____
// ====== output =====
==== then 1 ====
==== then 2 ====
Hast du auch den Fall betrachtet wenn ein Produkt gelöscht wird was bereits in einer Bestellung verwendet wurde?
Nein - generell behandelt diese API nicht alle möglichen Kombinationen sondern lieber möglichst viele unterschiedliche Aspekte (bspw. verschiede HTTP Verben, Auth (kommt noch) etc).
if (!product) {
return res.status(404).json({
message: 'Product Not Found'
});
}
The above code does not execute inside the orders.js file when you enter an invalid productId .Instead the .catch block executes where the code block sends a json(500). Anyone have a fix for this? Thanks in advance
Anyone gets the same result as mine with .delete() method? If I try to delete the order that was already deleted, I get the result with "DeleteCount: 0". Mongoose kind of putting deleted item in the cache or something. So it remembers the deleted items. So if I delete the order with the same id multiple time, it doesn't show "invalid id". Also, in there is message in the console telling me that .remove is deprecated and suggest that .deleteOne, .deleteMany, and .bulkwrite should be used instead.
Can you make a video using MySQL instead of MongoDB?
Hello! Does anyone know how can I solve the error : "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" when I get products by their ID? Thanks a lot!
@@joaobarbosa02 u were right! It was missing the "return" on my responses! Thank you so much!
16:44 this won't work, you will return the response to the next chain, which will try to set the header once more and throw an error, doing an if(promise){ } else { } branching instead and chaining the remaining execution that branches from a found product id onto the save() promise and letting the 404 close up the POST request instead solves this problem
can you please elaborate on it, a bit more?
I think this makes sense, but I can't fully understand it.
In post man it is showing json "product not found" thing.
But in the console I am getting a huge error. which is lines and lines of code that I can't paste here. Here's the look of it at the end.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:526:11)
at ServerResponse.header (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:771:10)
at ServerResponse.send (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:170:12)
at ServerResponse.json (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:267:15)
at E:\WebP\JSPractice
odePractice
estful-academind\api
outes\orders.js:27:29
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
POST /orders 500 770.054 ms - 31
(node:24860) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:526:11)
at ServerResponse.header (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:771:10)
at ServerResponse.send (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:170:12)
at ServerResponse.json (E:\WebP\JSPractice
odePractice
estful-academind
ode_modules\express\lib
esponse.js:267:15)
at E:\WebP\JSPractice
odePractice
estful-academind\api
outes\orders.js:42:29
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:24860) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:24860) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Thanks in advance!
@@hemanthvarmas The error printout you're getting seems large because its a stack trace, a lot of it coming from the express library source code. The most important part of the error, which will give you a clue about why the exception is being thrown is this: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client, and the line it refers to at the bottom of the stack trace here: E:\WebP\JSPractice
odePractice
estful-academind\api
outes\orders.js:42:29. This error is node trying to tell you that you are trying to set something in the response header twice, likely this is happening because you are setting a code in the header up in the method, and then trying to reset it on a separate conditional branch after it has been returned.
The second error you're getting is trying to tell you that you are letting an exception thrown inside a promise go unhandled, you can check the promise that the stack trace is pointing at and see if you're missing a catch block for it. The exception that is being thrown and going unhandled is most likely the error above where you are trying to set a field in a header multiple times after returning it.
I think you lost a lot of people at 15:00 when you cut and pasted some of the code. It wasn't exactly very visible what you were doing!
Does anyone did order.js in es6 method.
I am continuously gett error validation error , product path required in postman
If any please reply
Someone please help me.
I am always getting "quantity" as 1 no matter whatever I pass .
why to use const and not var or let?!
Because you want to protect those from being re-declared. You can assign new values of course, but you wouldn't ever want to expose it globally and allow it to be a new data type or data structure. Var is deprecated and should really not be used. Rule of thumb, start with const until you have to use let, do not use var.
For the error:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
Try with async-await:
router.post('/', async (req, res, next) => {
try {
const productFound = await Product.findById(req.body.productId).exec();
if (!productFound) {
return res.status(404).json({
message: "product not found"
})
}
const creatredProduct = new Product({
// ...
});
const documentCreated = await creatredProduct.save();
console.log('Create document', documentCreated);
const response = {
message: 'Created asset successfully',
// ...
};
res.status(201).json(response);
} catch (err) {
res.status(500).json({error: err.message});
}
});
As displayed on the console, the error description is:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
Thanks this worked for me
at 15:45 I have a question (I'm super noob) Why do I need 2 promises. Or in other words, why do I need to .then() blocks. Can't I just store the order, the response, and the metadata, all in the same .then() block? I promise you, I'm not trying to be a wise guy. I really do want to know, because I'm not very good at this. If someone takes the time to respond, I'll be grateful :)
How system will automatically detect product: productID in 5:16
Hello Academind, thank you.
My get request for the orders keeps return resolving to error which I find weird as I have your exact code
same here
if u sent a raw request from postman, change type from text to json. or u can post request using form-urlencoded method of postman
using Product.find() .exec() ....... gives me this error in postman = Product.find(...).exec(...).select is not a function"
I don't really know what's the reason. if I remove exec it works.
does Anyone know which kind of problem I'm facing?
i had the same issue, and i resolved it by placing .select() before .exec()
give that a shot. hope it works!
but patch?
Hello Max, love your videos, but in this tutorial I got stuck after implementing the router.post('/', ....), whenever I try to POST the order in postman software it comes out as
{
"error": {
"message": "document must have an _id before saving",
"name": "MongooseError"
}
}
and nothing gets posted in localhost:3000/orders
I mean why does the mongoose expect the `_id` to be there first, isn't the productId should suffice for that? I"m sorry if I'm vague , provide any explanation or suggestion that will help me guide
router.post('/products',function(req,res){
var product = new Products({
_id: mongoose.Types.ObjectId(),
name:req.body.name,
price:req.body.price
});
product.save().then(function(data){
res.send(data);
})
});
the logic at around 11:00 was very confusing. Can someone explain that to me?
That was required because he wanted to add more information to each record in the orders array, so he needs to loop through each order using the "map" and then adding the request element. This is not needed if you simply return the raw array.
Hi, Max. It is very hard to follow your fast scrolling at 15-16 minutes. Had to re-watch and re-play several times till I get it. Just a reminder to slow it down other time. Otherwise, great content!
Thank you for the hint Mindaugas, I'll try my best to keep that in mind :)
I still can't get the difference between a promise and "a real" promise. Could you explain in greater detail?
Me too was wondering about the same thing...Please Max enlighten on this.
Sorry for the confusion: I was not referring to different kinds of promises, just of different ways of getting them (directly chaining then()/catch() vs the need to use exec() first).
Academind yes, I got that, but what is really the difference? Are you getting different kinds of data when using exec() vs direct chaining?
Mongoose queries are not Promises. Queries do return a thenable, but if you need a real Promise you should use the exec method.
Is it? When we set Mongoose.Promise = global.Promise I assume Mongoose starts using global promise object, after all, if queries actually allow .then() as well as .catch() to be chained onto them what situation can actually require using .exec() in favor of not using it?
you can create same video mysql node js express same product(add,delete,edit,list),order(add,delete,edit,list), validation , join to table order and product and login ,registration authtoken routers all 14 video please created
I can understand mongoose.Promise = global.Promise; can you help me ?
Its kinda weird, when I pass req.params.orderId directly in Order.findById(), it cannot get the order details but when I assign the req.params.orderId value in id variable it works.. can someone tell me why?
By me POST with wrong product id doesn't work even without this check:
if(!product) {
return res.status(404).json({
message: 'Product not found'
});
}
I get this:
{
"message": "Product not found",
"error": {
"message": "Cast to ObjectId failed for value \"5a747be38f17ec1ea8255fd21\" at path \"_id\" for model \"Product\"",
"name": "CastError",
"stringValue": "\"5a747be38f17ec1ea8255fd21\"",
"kind": "ObjectId",
"value": "5a747be38f17ec1ea8255fd21",
"path": "_id"
}
}
What's the reason?
router.post('/', (req, res, next) => {
//ürün id geçerli mi?
Product
.findById(req.body.productId).exec()
.then(product => {
if (!product) {//bulunamayınca null geliyor
res.status(404).json({
message: 'Ürün Bulunamadı ' + req.body.productId,
})
} else {
const order = new Order({
_id: new mongoose.Types.ObjectId(),
product: req.body.productId,
quantity: req.body.quantity,
});
order.save()
.then(result => {
console.log(result);
res.status(201).json({
message: 'Sipariş Kaydedildi',
createdOrder: {
id: result._id,
product: result.product,
quantity: result.quantity,
request: {
type: req.method,
url: req.protocol + '://' + req.headers.host + req.url + 'orders/' + result._id
}
}
})
})
.catch(err=>{
console.log(err);
res.status(500).json({
error: err
})
})
}
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
});
});
Why this time don't need the new keyword to generate a new ObjectId? 4:53
Hello, did you find a solution yet?
I get an error when trying to POST an order
Here is the error
{
“error”: {
“ message “ : “ Class constructor ObjectId cannot be invoked without ‘ new ‘ “
}
}
th-cam.com/video/VKuY8QscZwY/w-d-xo.html
I don't know how to get the time-link in the comment so I copied the link at that duration. Please check the above link which should take you at 16:47 of the video. In that, you've put an IF condition thinking that if it passes, it won't go into the next then() method. But, it does. You do get the response as you've expected but try checking your console or put console.log() in the next then() method. You'll see it does go into that irrespective of the condition you've put.
If you find it, please fix it with a good approach. I've done it somehow but I don't think I've made it the way it should be.
please do everything a litte bit slower, i am so lost after min. 15
Sorry Luca, always hard to find the right balance between too fast and too slow. Did you try to change the playback speed in the TH-cam player? Maybe this helps a bit here.
I think it's difficult to follow because it doesn't show what shortcuts he's pressing. Also what he selected isn't what most people would think he is copying.
So here's the breakdown, where the problem starts to happen for a lot of folks.
If you go to your code before he starts moving anything before 15:00.
You should've just typed inside .then()
product => { ... and left it blank
take everything after the first catch block
and post it inside of the first .then(product => { ... })
then delete the catch(err => .. block because it will be redundant to the one you've just written for the .then(result => { .. order stored }