Coding

Managing Orders with Mongoose | Creating a REST API with Node.js

  • 00:00:02 welcome to another video in this series
  • 00:00:04 where we build a restful api with nodejs
  • 00:00:07 the previous videos we had a look at how
  • 00:00:10 we work on our products and how we store
  • 00:00:12 products in the database and that's all
  • 00:00:15 working now when I work on the orders
  • 00:00:17 and the interesting part here of course
  • 00:00:19 is that orders are connected to products
  • 00:00:22 so let's dive into that in this video
  • 00:00:28 so let's start working on that and the
  • 00:00:30 first thing I want to do is I want to
  • 00:00:32 create a model for my orders so I
  • 00:00:35 ordered J's file now copy the logic from
  • 00:00:39 the product JS file to import non-use
  • 00:00:41 and export a model at the end though the
  • 00:00:44 schema will be named order schema and
  • 00:00:47 I'll name the model order – now how
  • 00:00:52 should that look like do I want to have
  • 00:00:55 an ID and whatever unique ID per order I
  • 00:00:58 also need one important piece of
  • 00:01:01 information I need to know which product
  • 00:01:04 was ordered
  • 00:01:05 now you could of course create a way
  • 00:01:08 more complex setup where you have carts
  • 00:01:10 so shopping carts which comprise a
  • 00:01:13 couple of our products and quantities I
  • 00:01:17 want to start and stick simple here I
  • 00:01:20 want to say okay I got an order and that
  • 00:01:22 order is connected to one product which
  • 00:01:25 I ordered so how does this work then
  • 00:01:27 I'll add a product key and I'll set this
  • 00:01:32 equal to an object now the type here
  • 00:01:36 will actually also be an object ID
  • 00:01:40 because I will store the ID of the
  • 00:01:43 product which is related to this order
  • 00:01:46 now there's something important we're
  • 00:01:48 now creating like a relation and MongoDB
  • 00:01:52 is a non relational database you can
  • 00:01:55 kind of rebuild these relations as we're
  • 00:01:57 about to do that and that is okay to
  • 00:02:00 some degree but if you find yourself
  • 00:02:03 building a lot of relations and sticking
  • 00:02:06 very much in that sequel database world
  • 00:02:10 then you might indeed wanna pick a
  • 00:02:12 sequel database because you might not
  • 00:02:14 need the advantages of a no sequel
  • 00:02:16 database like MongoDB but you will just
  • 00:02:19 get all the disadvantages if you work
  • 00:02:22 with a lot of relations now this one
  • 00:02:24 relation here that's perfectly fine but
  • 00:02:27 I just want to bring this to your
  • 00:02:28 attention so let's set up the relation
  • 00:02:31 here then and as I said first of all
  • 00:02:33 let's assign you type to be an object ID
  • 00:02:36 and then there's an important keyword
  • 00:02:38 ref you need to use ref here to
  • 00:02:40 configure this
  • 00:02:41 type and ref should now hold a string
  • 00:02:45 with the name of the model you want to
  • 00:02:47 connect this model to know if we have a
  • 00:02:50 look at our product JS file we see that
  • 00:02:52 the name is product so it's this name we
  • 00:02:55 assigned here and that's the name I now
  • 00:02:57 always use here I want to connect this
  • 00:02:59 schema with my product and with that I
  • 00:03:04 store my order where I say we ordered
  • 00:03:08 this product now let's say a product or
  • 00:03:12 excuse me an order also knows a quantity
  • 00:03:14 here we could set a type to be number
  • 00:03:18 and we can set required to true because
  • 00:03:21 I want to have a quantity on each order
  • 00:03:23 you could of course also make this
  • 00:03:24 optional and you could also say okay I
  • 00:03:27 might not require it I'll just set a
  • 00:03:30 default which is one that's also an
  • 00:03:34 option now just required and default
  • 00:03:36 together don't make a lot of sense but
  • 00:03:38 in this case you're saying you don't
  • 00:03:40 need to pass me a quantity if you pass
  • 00:03:43 me nothing I'll use that default of one
  • 00:03:45 so we'll always store a quantity in the
  • 00:03:48 database it's just going to be our
  • 00:03:50 default quantity if no data there are no
  • 00:03:53 additional information is passed and
  • 00:03:54 that is a very simple order look at the
  • 00:03:56 product we got the quantity the price as
  • 00:03:59 part of the product so we can calculate
  • 00:04:01 the total price and with that we got a
  • 00:04:04 schema setup for orders now let's use
  • 00:04:06 that scheme and our order J's file
  • 00:04:09 before we fetch all orders let's work on
  • 00:04:12 hosting them now for that I'll import
  • 00:04:15 two things I'll import Mongoose to
  • 00:04:17 create an ID so I'll simply require
  • 00:04:20 Mongoose here and I will of course also
  • 00:04:24 import my order model from the models
  • 00:04:30 file and there from the order J's file
  • 00:04:32 with there we can create a new order so
  • 00:04:36 I'll create an order but I'll treat it
  • 00:04:38 differently with new order so using our
  • 00:04:41 model as a constructor which we can of
  • 00:04:43 course and then passing a JavaScript
  • 00:04:45 object where we will configure it now
  • 00:04:47 I'll set the ID equal to Mongoose types
  • 00:04:52 object ID executed as a function to
  • 00:04:55 automatically generate an idea then I
  • 00:04:58 can set the quantity to request body
  • 00:05:03 quantity though that might not be sad
  • 00:05:07 sodas might be null but it should still
  • 00:05:09 work we'll see if it does and I also
  • 00:05:12 need to set my product and now this
  • 00:05:14 needs to be the idea of the product
  • 00:05:16 we're connected to and I expect to get
  • 00:05:18 this a request body product ID maybe
  • 00:05:22 this also means that back in the order
  • 00:05:25 model we probably want to set this to be
  • 00:05:29 required so that we can't pass null here
  • 00:05:34 so back here in our order J's file the
  • 00:05:37 routes file we're now creating our order
  • 00:05:41 or storing it in the database where
  • 00:05:43 we're trying we're setting it up we
  • 00:05:45 cannot store it by a chaining save and
  • 00:05:47 then on save we can chain then or
  • 00:05:54 actually we can't chain exit to turn it
  • 00:05:56 into a real promise then and catch are
  • 00:05:58 also provided on the return values by
  • 00:06:01 default but that's they're not a real
  • 00:06:03 problems with the ex ecute is so now we
  • 00:06:05 can add them and catch and then we can
  • 00:06:10 use the result we're getting back here
  • 00:06:13 you may be log it to the console and of
  • 00:06:17 course to also resend a status code of
  • 00:06:19 201 where we essentially for now send a
  • 00:06:22 simple results but response we're going
  • 00:06:24 to find you this where a just return the
  • 00:06:27 result and when we catch an error I'm
  • 00:06:31 going to console lock that error here
  • 00:06:34 and I'm going to return a response with
  • 00:06:36 status code 500 where I send an error or
  • 00:06:40 property that holds the error we got and
  • 00:06:43 I'll remove the default damage response
  • 00:06:45 we used previously let's find out if
  • 00:06:48 that works now for that let's go back
  • 00:06:51 and let's first of all get the list of
  • 00:06:53 products and restart our server first of
  • 00:06:58 all so let's get a list of products
  • 00:07:00 maybe this one with that ID let's copy
  • 00:07:03 the ID let's create a new post request
  • 00:07:06 which targets slash orders to send a
  • 00:07:08 post
  • 00:07:09 to that endpoint not send a JSON body
  • 00:07:13 which should be a normal JSON object
  • 00:07:16 where I do set you know this is
  • 00:07:19 important where I do set quantity and
  • 00:07:22 product ID so I'll add product ID as a
  • 00:07:28 key here and past the idea just copied
  • 00:07:31 and I'll set quantity as a key here and
  • 00:07:35 set this to two now if I had sent or I
  • 00:07:40 get an error accident work
  • 00:07:44 yeah true we're saving here so generally
  • 00:07:47 that was true
  • 00:07:47 exit gives you a real promise whereas
  • 00:07:50 normal queries and save is not a curious
  • 00:07:53 this but queries we're used find for
  • 00:07:56 example these give you back a Venn
  • 00:07:59 method but no catch method and then you
  • 00:08:01 can use X Act to turn it into a real
  • 00:08:03 promise for save you actually get a real
  • 00:08:05 promise by default so that out of the
  • 00:08:08 way let's try that again now here we see
  • 00:08:11 we created a new object with its own ID
  • 00:08:15 which is different to the Product ID of
  • 00:08:17 course we store it the product ID and we
  • 00:08:19 got the quantity of two now let's all
  • 00:08:22 try not passing a quantity if I now hit
  • 00:08:25 Send we see we also get this default
  • 00:08:27 quantity of 1 and if I now don't send an
  • 00:08:31 ID so I don't send anything we get an
  • 00:08:34 error that the product is required which
  • 00:08:36 makes sense so now we can successfully
  • 00:08:39 create new orders let's make sure we can
  • 00:08:41 also view all orders by going to our
  • 00:08:44 general get route here and let's use
  • 00:08:46 order here together with fine with no
  • 00:08:49 arguments to find all orders if you pass
  • 00:08:52 an argument to find it would be an
  • 00:08:53 object that describes the object you
  • 00:08:55 want to find just as we use the for
  • 00:08:57 update and delete but here I want to
  • 00:08:59 find all orders and I simply will
  • 00:09:02 execute X X to again turn it into a real
  • 00:09:05 promise here and then chain then and
  • 00:09:07 catch and then let's see what we can do
  • 00:09:10 here let's use all the docs we get back
  • 00:09:12 and for now simply return them with a
  • 00:09:14 status code of 200 Jason Docs like that
  • 00:09:18 and for an error I will send a status
  • 00:09:22 code of
  • 00:09:23 500 where I said Jason to an object were
  • 00:09:27 we store and return the error now if
  • 00:09:32 dad's setup let's save this and let's
  • 00:09:34 try it out by sending a get request to
  • 00:09:38 orders like this for hit Send here I get
  • 00:09:42 all the orders I did create so the two
  • 00:09:45 with quantity two I stored and the one
  • 00:09:48 with quantity one so this is now my get
  • 00:09:54 request
  • 00:09:55 now let's already work on the response
  • 00:09:57 layout so here for example I don't want
  • 00:10:00 to return that the part and I want to
  • 00:10:03 return more information than just the
  • 00:10:05 array of items so I'll add select prior
  • 00:10:08 to exit and just select the product and
  • 00:10:12 the quantity field and the ID let's say
  • 00:10:16 and then again here I'll return an
  • 00:10:19 object where I have count which is Doc's
  • 00:10:22 length and where I then also have my
  • 00:10:26 orders which is now docks and where I
  • 00:10:29 have my request object let's say with a
  • 00:10:32 type of get because I also want to
  • 00:10:37 support details on our individual order
  • 00:10:39 so get to a URL which would be HTTP
  • 00:10:43 localhost 3,000 orders slash and then it
  • 00:10:48 would be our ID of that document now to
  • 00:10:53 get this back I made a mistake
  • 00:10:57 of course shouldn't return orders like
  • 00:10:59 this I should map it here to get the
  • 00:11:02 individual doc and then return a new
  • 00:11:04 object here for that document we got
  • 00:11:07 where I then have my ID that a stock
  • 00:11:10 underscore ID where I have my product
  • 00:11:14 that is dark Product ID so just excuse
  • 00:11:19 me just product what we got here suggest
  • 00:11:21 product and when we didn't got the
  • 00:11:23 quantity which is stock quantity and
  • 00:11:25 where we then pass our request object
  • 00:11:28 and where we now can use dark underscore
  • 00:11:31 ID like this now if we save this we get
  • 00:11:36 the same logic as an hour
  • 00:11:37 product routes I get this more
  • 00:11:39 structured response with more
  • 00:11:41 information the same makes sense for
  • 00:11:43 creating a new object here if we
  • 00:11:47 succeeded I might want to return a
  • 00:11:50 message where I say order stored and
  • 00:11:54 where I then pass a URL where you can
  • 00:11:57 get more information like the type here
  • 00:12:00 you could then set the type to get and
  • 00:12:04 the URL would essentially be the same as
  • 00:12:06 we use up here so I can just copy that
  • 00:12:09 URL down to this return a response here
  • 00:12:15 access it on the result I get this is
  • 00:12:18 the object that was created and of
  • 00:12:20 course also maybe have a created order
  • 00:12:25 object here that holds the information
  • 00:12:28 about the created order and there we
  • 00:12:30 could output the ID from result ID the
  • 00:12:34 product from result product and of
  • 00:12:38 course the quantity from result quantity
  • 00:12:41 and if we tried that out by creating a
  • 00:12:43 new order by sending a post request to
  • 00:12:45 orders with the body we used before but
  • 00:12:49 maybe with a valid product ID so let's
  • 00:12:53 reuse that product ID we already used in
  • 00:12:55 the past if you do it like this product
  • 00:12:59 ID should be the key name here then we
  • 00:13:01 store this and we see that nice a
  • 00:13:03 response by the way if we pass an
  • 00:13:06 invalid ID for a product doesn't exist
  • 00:13:09 we also store debt so this also works
  • 00:13:15 now we're storing a bunch of orders on
  • 00:13:18 products that don't actually exist in
  • 00:13:21 the database so that is something we'll
  • 00:13:23 have to make sure that it doesn't happen
  • 00:13:25 so let's turn or let's add some logic to
  • 00:13:30 control this we want to make sure that
  • 00:13:33 we can't create new orders for products
  • 00:13:36 for products we don't have so here in
  • 00:13:38 our post method in the orders J's file
  • 00:13:41 now first of all check if we actually do
  • 00:13:45 have a product for a given ID now to do
  • 00:13:48 that I'll import product here
  • 00:13:51 by calling required and going to the
  • 00:13:55 models folder and then the product file
  • 00:13:56 and then I can use a static method on
  • 00:14:00 product here call find PID and search
  • 00:14:05 for a request body Product ID and now
  • 00:14:11 what I can do is if this succeeds then I
  • 00:14:16 want to continue with creating the order
  • 00:14:18 otherwise I want to return an error here
  • 00:14:22 I will simply return a response with
  • 00:14:25 status code 500 where I return an object
  • 00:14:29 where I say message product not found
  • 00:14:32 and as always you could all return some
  • 00:14:34 machine readable error code here and
  • 00:14:37 pass the detailed error object now in
  • 00:14:41 the Dan block here I'll actually get my
  • 00:14:44 product or my document but it is a
  • 00:14:47 product let's knit maybe name it like
  • 00:14:49 this and then in here I can execute the
  • 00:14:52 average code here to store that new to
  • 00:14:58 store it that new order however now we
  • 00:15:00 have a nice level of nesting which we
  • 00:15:02 don't want when using promises so what
  • 00:15:05 we can do is I can simply return orders
  • 00:15:08 safe which does return a promise as you
  • 00:15:11 see and then I can use that the ban and
  • 00:15:20 the catch blocks and chain them after
  • 00:15:22 here just means that this catch block
  • 00:15:25 here isn't too useful anymore because
  • 00:15:27 it'll never execute because we have this
  • 00:15:30 outer catch block here so now with that
  • 00:15:32 we got a set up where I check if we do
  • 00:15:35 have a product before I then try to save
  • 00:15:38 it and we then execute all the our steps
  • 00:15:41 for creating the order and for it
  • 00:15:43 returning a response and if we don't
  • 00:15:45 have our product here well then we'll
  • 00:15:48 get into disk catch block where we
  • 00:15:50 return the error anyways
  • 00:15:51 so now with that if we save this and we
  • 00:15:53 try again to create a product which has
  • 00:15:56 an invalid ID it still succeeds do you
  • 00:16:00 know why well remember what we did in
  • 00:16:03 that products jeaious
  • 00:16:04 file there we also check we do find a
  • 00:16:07 product here but we check this in a
  • 00:16:12 success case because remember if you
  • 00:16:14 pass an ID for which no product is found
  • 00:16:18 then you don't get an error
  • 00:16:20 you just get null for product in this
  • 00:16:23 case so actually we want to check that
  • 00:16:26 if product if not product which means if
  • 00:16:30 it's knowledge then we want to return
  • 00:16:32 the response where we set the status
  • 00:16:34 code to 404 and where we then can return
  • 00:16:37 our response where we may be say message
  • 00:16:40 product not found and yeah that's it and
  • 00:16:44 since I returned all subsequent code
  • 00:16:47 won't be executed in this case now with
  • 00:16:49 dad if I send this now I get product not
  • 00:16:53 found here and with that again if I do
  • 00:16:57 get all my products and I dare for fetch
  • 00:17:04 a valid ID of a product and I now create
  • 00:17:07 a post request to orders again and I do
  • 00:17:10 use such a valid ID it again succeeds so
  • 00:17:14 this works but we can't store orders for
  • 00:17:17 products we don't have which of course
  • 00:17:18 is very useful now let's continue let's
  • 00:17:21 get information about the individual
  • 00:17:23 order well there we can't just use
  • 00:17:25 product excuse me not product order and
  • 00:17:27 call find by ID and pass request parents
  • 00:17:33 order ID as an argument because we named
  • 00:17:36 it order ID here call X sector turn it
  • 00:17:40 into a real promise and then use catch
  • 00:17:42 and then again and here we'll get our
  • 00:17:45 document
  • 00:17:45 you couldn't alter name it order because
  • 00:17:47 it is an order whatever you want
  • 00:17:48 and you can return a response with
  • 00:17:51 status code 200 and then there a JSON
  • 00:17:55 object where again we can pass our
  • 00:17:59 information about the object we got so
  • 00:18:03 there we could now return order and that
  • 00:18:09 is equal to the order argument we get
  • 00:18:11 here from Mongoose and add our request
  • 00:18:14 metadata object where we can say yeah
  • 00:18:17 you can
  • 00:18:18 course send us a get request maybe to
  • 00:18:21 the following URL to get all requests so
  • 00:18:24 the URL would be H via local host 3000
  • 00:18:28 slash orders to get all the orders and
  • 00:18:31 that's just one example we could use as
  • 00:18:32 always and that here in the error case I
  • 00:18:35 want to return a response with status
  • 00:18:37 killed 500 where we use Jason to of
  • 00:18:41 course all returned an object where I as
  • 00:18:44 always wrap this error in my error
  • 00:18:47 property now with that finally for all
  • 00:18:51 let's try it out I guess
  • 00:18:52 so let's first of all copy that order ID
  • 00:18:56 we have here and let's try a get request
  • 00:19:01 to this order ID and there we go now we
  • 00:19:06 also get that link to fetch all orders
  • 00:19:09 we can click on that and we see all the
  • 00:19:11 orders we created quite a bit so time
  • 00:19:14 for a delete function and let's work on
  • 00:19:16 that delete function here there again I
  • 00:19:19 can use order and then remove and pass
  • 00:19:23 an object to identify what I want to
  • 00:19:25 remove I want to remove that object that
  • 00:19:27 has an ID that matches my request
  • 00:19:30 parents order ID property because again
  • 00:19:34 I named it order ID here and then I can
  • 00:19:37 chain x''k then and catch and a so often
  • 00:19:43 in catch I just want to return my error
  • 00:19:46 so I'm going to copy that code and you
  • 00:19:48 could of course also outsource this into
  • 00:19:50 some general function you then always
  • 00:19:52 call that returns this response and in
  • 00:19:55 the Dan block I want to return a
  • 00:19:58 response so I get my result here won't
  • 00:20:01 return a response where I essentially
  • 00:20:03 have a message that could be order
  • 00:20:06 deleted and the request could suggest to
  • 00:20:11 create a new order by posting to orders
  • 00:20:14 and there we needed to send an object a
  • 00:20:17 body where we will pass the product ID
  • 00:20:22 which will be an ID whatever type you
  • 00:20:26 want to describe here and then
  • 00:20:31 quantity which is a number something
  • 00:20:37 like that now if we do that let's again
  • 00:20:40 get all orders because we certainly have
  • 00:20:43 too many and then let's fetch one of the
  • 00:20:47 orders maybe this one and let's now try
  • 00:20:50 sending a delete request to this
  • 00:20:52 endpoint if I do that the order was
  • 00:20:55 deleted indeed and if I try to get
  • 00:20:59 information for that order it fails
  • 00:21:01 orders now because we don't find it now
  • 00:21:04 that of course means that in our get
  • 00:21:06 requests here where we find by ID I
  • 00:21:09 should also add a if check if not order
  • 00:21:12 so if it's null as is in the example I
  • 00:21:14 just ran was then I probably want to
  • 00:21:18 return a response where I set the status
  • 00:21:20 code to 404 and return an object where I
  • 00:21:23 say message order not found so that I
  • 00:21:29 avoid having cases like this where I get
  • 00:21:32 order now which you could use if that's
  • 00:21:34 your requirement but I don't want it now
  • 00:21:37 if I try to fetch details for an order
  • 00:21:39 that doesn't exist I get a 404 error and
  • 00:21:42 that again was a lot of work but now we
  • 00:21:45 worked on the orders side queue we're
  • 00:21:48 storing that relation now querying this
  • 00:21:51 relation and in general now working with
  • 00:21:53 all that data and seeing how we can
  • 00:21:56 further evolve our restful api is what
  • 00:21:59 we'll dive into next