- 00:00:02 welcome to another video in this
- 00:00:04 building a restful service with no js'
- 00:00:07 serious the last video we added Mongoose
- 00:00:10 and we connected therefore our MongoDB
- 00:00:12 database and we worked a lot on the
- 00:00:14 products related routes in this video I
- 00:00:17 want to find you an hour setup there a
- 00:00:20 bit add validation so that only valid
- 00:00:23 data makes it into our database and also
- 00:00:27 come back to these restful constraints I
- 00:00:29 showed you earlier this serious because
- 00:00:32 right now our responses we give back
- 00:00:36 from our endpoints here are not really
- 00:00:39 dead great so let's work on both in this
- 00:00:41 video
- 00:00:45 let's start by adding validation now for
- 00:00:49 that most interesting class is the post
- 00:00:52 route here where we create new products
- 00:00:56 and there we store an ID which we
- 00:00:58 automatically generate so nothing to
- 00:01:01 validate here this will be unique and so
- 00:01:03 on but we also store a name and a price
- 00:01:05 and what happens if a user passes let's
- 00:01:09 say a string as a price well let's find
- 00:01:12 out let's go back to postman create a
- 00:01:14 new post request to products let's work
- 00:01:17 on the body and the body now needs to
- 00:01:19 change again should be a normal JSON
- 00:01:22 object here ray set the name to
- 00:01:25 something something awesome and then I
- 00:01:32 set the price to hello which doesn't
- 00:01:36 look like a correct price if I sent this
- 00:01:39 and restart my server which I adjusted
- 00:01:43 so if I sent this I do get back an error
- 00:01:47 cast number failed for a value hello so
- 00:01:50 that's great what important lecture we
- 00:01:53 can already take away we can't store
- 00:01:55 strings as numbers and so on this is
- 00:01:57 already something mongoose checks for us
- 00:01:59 and it correctly throws an error if we
- 00:02:02 try to do so however what happens if we
- 00:02:05 don't pass a price but just pass a name
- 00:02:07 then we still get back a valid response
- 00:02:10 and if I now get all my products you see
- 00:02:14 we created a product without a price
- 00:02:16 that is not how it should work so I'll
- 00:02:20 go back to my product model and there
- 00:02:24 where I set the values to string a
- 00:02:25 number we can also pass an object which
- 00:02:28 does not mean the type as an object but
- 00:02:31 now we can provide a more detailed
- 00:02:33 configuration we can set up a type
- 00:02:36 property here where we can still set
- 00:02:38 this to number so now we had the same as
- 00:02:40 before but we can also pass more
- 00:02:42 configuration like for example we could
- 00:02:45 set required to true here and this does
- 00:02:49 just what it sounds like it makes sure
- 00:02:51 that this field is required if I now
- 00:02:53 save this and I try to send that same
- 00:02:56 post request from before again
- 00:02:58 I now get an error that path price is
- 00:03:01 required and this of course makes sense
- 00:03:05 because well it is required I don't want
- 00:03:09 to allow this right excess and the same
- 00:03:13 can be done for the name of course here
- 00:03:16 I'll now also set is to type string and
- 00:03:18 require this and if I now send this here
- 00:03:22 sorry without setting a name so let's
- 00:03:25 just set some names property which
- 00:03:27 doesn't exist now this also fails
- 00:03:31 because price is required and name is
- 00:03:34 required if I do set a name to something
- 00:03:38 awesome and if I then do set a price to
- 00:03:41 something awesome then it succeeds if I
- 00:03:45 now add a third argument here like sales
- 00:03:49 price which I set to 999 and I said this
- 00:03:54 it also succeeds and if we get all
- 00:03:57 products we see that here know where the
- 00:04:02 sales price was safe though and that
- 00:04:05 makes a lot of sense because if you have
- 00:04:06 a look at our back end just sending the
- 00:04:10 sales price as an argument to our route
- 00:04:12 doesn't do anything because here we're
- 00:04:15 configuring the product we plan on
- 00:04:17 storing and there we never extract the
- 00:04:19 sales price we never assign it to a
- 00:04:21 property in our object which is going to
- 00:04:24 get stored so we can send which every
- 00:04:26 day that we want we're just making sure
- 00:04:28 that the day that we do expect is valid
- 00:04:31 and this is now the case with the set up
- 00:04:33 we well set up here now let me quickly
- 00:04:37 clean up that data here by sending a
- 00:04:39 couple of delete requests so I'll delete
- 00:04:42 this product which doesn't have a valid
- 00:04:44 price and thereafter let me quickly
- 00:04:48 again grab all products whoops
- 00:04:51 without that ID which correctly failed
- 00:04:54 because we just deleted it and let me
- 00:04:56 also delete one of these something
- 00:04:58 awesome products here or if you want of
- 00:05:01 course both so let's delete that
- 00:05:03 two now that also Rachelle's us some
- 00:05:06 other issue i want to work on in this
- 00:05:08 video the response now this is not a
- 00:05:10 good response in at cert
- 00:05:11 doesn't fulfill the constrains I
- 00:05:14 mentioned earlier in this video series
- 00:05:16 where the responses should be all kind
- 00:05:18 of self-destructive so what we want to
- 00:05:21 do is provide better responses let's
- 00:05:23 start in products file here which is the
- 00:05:27 only file where we really do something
- 00:05:28 with the data and there let's take a
- 00:05:32 closer look I do have my get request
- 00:05:37 where I get all my Doc's and we can't
- 00:05:40 improve that because if we send such a
- 00:05:42 get request we clearly whoops without
- 00:05:46 the idea again we clearly get back a
- 00:05:50 response that is interesting to us it
- 00:05:52 gives us all the IDS and we know that we
- 00:05:55 can take the ID and appended at the end
- 00:05:57 of the URL to get data for this object
- 00:06:00 at but this is not necessarily something
- 00:06:04 you know when you're a newcomer to this
- 00:06:07 API so it would be nice if we could also
- 00:06:09 provide a link here which you could then
- 00:06:12 programmatically fetch to send another
- 00:06:15 request to it and maybe we also want to
- 00:06:18 send some metadata like the amount of
- 00:06:20 items we fetched so overall I don't just
- 00:06:23 want to return the docs here as the
- 00:06:25 response I want to return more I'll get
- 00:06:28 rid of the console log which I don't
- 00:06:29 really need anymore
- 00:06:30 and now I will create my response object
- 00:06:35 here you can name this whatever you want
- 00:06:37 and in this object I want if account for
- 00:06:40 example and I will simply set is equal
- 00:06:43 to Doc's length so that I give some meta
- 00:06:46 information about the amount of elements
- 00:06:48 we fetched thereafter I'll add a
- 00:06:51 products property which now will be an
- 00:06:54 array of all the products now there I'm
- 00:06:58 not interested in this strange
- 00:06:59 underscore underscore V thing which
- 00:07:01 seems to be some internal thing so that
- 00:07:04 is something I don't want to pass along
- 00:07:06 I can make sure that I don't fetch it by
- 00:07:09 adding some other method prior to exit
- 00:07:12 the Select method where I can define
- 00:07:15 which fields I want to select and you
- 00:07:17 can pass a string here and there you can
- 00:07:20 pass name price and underscore ID and
- 00:07:24 this means I will
- 00:07:25 fetch these fields and no other field
- 00:07:27 and this is a great way of controlling
- 00:07:29 which data you actually want to fetch so
- 00:07:31 now if I attach Docs here it will be an
- 00:07:34 array of talks without that strange
- 00:07:36 underscore D thing and we can see this
- 00:07:38 if we just save that and send again a
- 00:07:40 get request to fetch all products now
- 00:07:43 these are a new structure now we don't
- 00:07:46 see the count field because I'm not
- 00:07:48 using my new response constant here I
- 00:07:50 should return that instead of the docs
- 00:07:52 so now if I do that again you see now we
- 00:07:55 got an object with count two products
- 00:07:57 and then the products and then as I said
- 00:08:00 would be interesting to also have more
- 00:08:01 information on the individual product
- 00:08:03 like the URL that leads us to the detail
- 00:08:06 information for that product so for that
- 00:08:09 I'll actually change my Doc's array here
- 00:08:12 I can use the normal map method for that
- 00:08:14 to basically map it into a new array
- 00:08:17 there I'll get my individual document I
- 00:08:20 fetched and I will return a new version
- 00:08:23 of it now that new version will use all
- 00:08:28 the old data and for that we could use
- 00:08:32 the object spread operator if it is
- 00:08:34 supported by the node.js version you're
- 00:08:36 using but you can also map it manually
- 00:08:38 to say name is doc name and price is
- 00:08:42 dark price and then underscore ID is doc
- 00:08:47 underscore ID but then also pass
- 00:08:51 something like URL which could be a
- 00:08:54 JavaScript object where we or maybe
- 00:08:58 request which could be type where we say
- 00:09:01 okay you can send a get request and this
- 00:09:03 is just meta information you can write
- 00:09:06 this in whichever way you want pass
- 00:09:08 whichever information you want now I
- 00:09:10 want to pass information about which
- 00:09:12 kind of requests do you have to send to
- 00:09:14 which URL to get more information about
- 00:09:16 this object so here it would be a get
- 00:09:19 request which you send to given URL that
- 00:09:24 would be and now it's the URL of our
- 00:09:27 service here so in my case is HTTP a
- 00:09:30 localhost but of course you can also
- 00:09:32 dynamically fetch this to get the ID off
- 00:09:35 the service you are running on or you
- 00:09:38 can of course
- 00:09:38 also hard-code the domain in here which
- 00:09:41 you're going to use in the end so I'm
- 00:09:44 going to fetch my address here localhost
- 00:09:48 3000 to be precise but then you would
- 00:09:51 have to connect to products
- 00:09:56 slash and then dark underscore ID
- 00:10:01 whoops should be dot ID now if I save
- 00:10:04 this and I send a get request we get
- 00:10:08 back dead extra information with the URL
- 00:10:11 I can send a get request you and I can
- 00:10:14 indeed do this by simply clicking on it
- 00:10:15 where I get detailed information for
- 00:10:18 dead given object so this is now how we
- 00:10:22 should style this and how we should
- 00:10:24 structure this this is a better response
- 00:10:26 for getting all the documents and of
- 00:10:29 course you can find you just totally to
- 00:10:31 your needs now let's have a look at the
- 00:10:34 AMA routes if we created a new object
- 00:10:37 right now I simply return a message
- 00:10:41 which is okay but maybe not this message
- 00:10:44 so we could say created object or
- 00:10:47 created product successfully though that
- 00:10:49 is kind of a redundant message because
- 00:10:53 we do have status code 200 one but still
- 00:10:55 let's keep it then create a product make
- 00:10:58 sense but I don't just want to paste in
- 00:11:01 the result here instead because let's
- 00:11:05 maybe first have a look because if I do
- 00:11:07 send such a post request here with the
- 00:11:11 body I have here without the sales price
- 00:11:14 maybe if I sent this what I get back as
- 00:11:18 a response is also again with this
- 00:11:20 strange V thing and so on so what I
- 00:11:23 could do is I could also simply return a
- 00:11:26 new object here where may be manually
- 00:11:30 mapped name to result name price to
- 00:11:33 result price and ID to result ID but
- 00:11:39 where I then also and my request object
- 00:11:42 I used before where I set the type equal
- 00:11:45 to get and the URL to the same URL as
- 00:11:48 above to gift user an idea about where
- 00:11:51 to say
- 00:11:52 a subsequent request to get detailed
- 00:11:54 information about that new object the
- 00:11:57 one difference is of course that here
- 00:11:58 I'm not accessing doc ID but result ID
- 00:12:01 so this would now be a better response
- 00:12:03 for creating products if we have a look
- 00:12:06 this looks good now we get this type of
- 00:12:08 response and feel free to continue on
- 00:12:11 your own of course to practice this we
- 00:12:13 can do the same for the other routes too
- 00:12:15 like here when we get data about one
- 00:12:18 single object
- 00:12:19 if I do send such a get request here we
- 00:12:23 also get back that we thing the rest
- 00:12:25 actually might be fine though you could
- 00:12:26 also pass some meta information about
- 00:12:28 where to send a request to get a list of
- 00:12:30 all objects maybe so that is something
- 00:12:33 you can change on that get route for a
- 00:12:36 single object so on this route here for
- 00:12:41 one I can add select here to say I only
- 00:12:45 want to name the price and the ID and
- 00:12:47 then as I just mentioned you can adjust
- 00:12:50 the response here to not just give back
- 00:12:53 the product which is your document but
- 00:12:55 also that request metadata where you say
- 00:12:58 yeah you could also send a get request
- 00:13:02 to a URL and that URL which be HDPE
- 00:13:07 localhost / products to get a list of
- 00:13:10 all products and of course you could
- 00:13:12 pass also some description property
- 00:13:14 where you say get all products so that
- 00:13:17 it's clearer what you're doing here or
- 00:13:19 use some identifiers like get all
- 00:13:22 products that could be more machine
- 00:13:24 readable I'll remove that but you can
- 00:13:27 style this and set this up in whichever
- 00:13:29 way you need it where you want it for
- 00:13:31 your API it is something you should
- 00:13:33 always keep in mind though you create
- 00:13:37 descriptive api's if you plan on using
- 00:13:40 them publicly if it's only for you you
- 00:13:42 might not need that but if you want to
- 00:13:44 create an API that's used by other
- 00:13:46 people you should be clear about how to
- 00:13:48 use it and you do that by using it like
- 00:13:50 this and for that let's also do the same
- 00:13:54 for patching here we obviously also
- 00:13:58 update and we then return the result of
- 00:14:01 that operation which isn't that
- 00:14:02 meaningful it's just is the strange set
- 00:14:05 of now
- 00:14:06 so there I could also just pass nothing
- 00:14:08 that's also valid or simply pass
- 00:14:12 something like an object where we have a
- 00:14:14 message product updated and then again
- 00:14:19 our request object to know that you can
- 00:14:22 send a get request queue a URL to get
- 00:14:25 the details about the new product and
- 00:14:27 that would be localhost / products / and
- 00:14:31 then the ID which we fetch from our URL
- 00:14:35 here so that would be a meaningful
- 00:14:38 response for patching so let's try this
- 00:14:41 out – if I want to send a patch request
- 00:14:43 to this URL and there I do instead
- 00:14:46 indeed set a meaningful body well let's
- 00:14:51 do that on the first tab where I already
- 00:14:54 configured this a bit better so let's
- 00:14:57 grab some ID here which I want to patch
- 00:14:59 let's turn this to a patch request and
- 00:15:02 then remember here the body is array
- 00:15:04 where we got a couple of objects
- 00:15:06 describing the operations we want to do
- 00:15:08 like here we would set the prop name
- 00:15:12 property – let's say name we want to
- 00:15:15 change the name of a product and then
- 00:15:17 the value will be something more useful
- 00:15:23 if I now send this I get back this
- 00:15:27 updated response and I can send a get
- 00:15:29 request to dis of course and fail oh
- 00:15:34 because I of course should encode the
- 00:15:37 port into that URL queue so that is
- 00:15:41 something I also need to do up here
- 00:15:42 where I return the data for a single
- 00:15:45 Product ID so this should be the full
- 00:15:47 domain of course so with that fixed
- 00:15:50 let's try this again let's again patch
- 00:15:53 this object here and then simply send a
- 00:15:57 get request and now we get that data for
- 00:15:59 this changed object and with that for
- 00:16:04 deleting we also might do something
- 00:16:06 comparable here we try to delete this
- 00:16:10 object and if we succeed I can either
- 00:16:13 send an empty object or again something
- 00:16:15 with a message where I say product
- 00:16:17 deleted and here
- 00:16:19 I don't need to send in a link to the
- 00:16:21 product because it was deleted but we
- 00:16:23 could add our request object here maybe
- 00:16:26 to show hey you could also send a post
- 00:16:28 request to some other URL so here would
- 00:16:32 be HTTP localhost 3,000 products to
- 00:16:36 create a new product there you will need
- 00:16:39 to send data and that data then would
- 00:16:44 simply be in the form of having a name
- 00:16:48 which is a string and price which is a
- 00:16:54 number and with that we would give
- 00:16:56 instructions what the request body
- 00:16:58 should look like maybe we name this body
- 00:17:00 therefore so now if we save this and we
- 00:17:03 delete our object here we get back this
- 00:17:07 language cells hey you can send a post
- 00:17:09 request to this URL and if you pass that
- 00:17:11 payload then you will create a new
- 00:17:13 product so these are more meaningful
- 00:17:16 responses and you can as I said
- 00:17:18 fine-tune them to your needs you might
- 00:17:20 need different responses obviously I
- 00:17:22 think we spent enough time on that
- 00:17:24 now one thing because just as I said I
- 00:17:26 want to work on it's just application
- 00:17:28 warning which you also might have seen
- 00:17:31 and which you may be also asked about
- 00:17:32 already now this is not a problem you
- 00:17:35 could ignore it but we also can fix it
- 00:17:38 by going back to the app.js file and
- 00:17:41 there when we set up mangu is right when
- 00:17:43 we connect it there I can also say
- 00:17:47 Mongoose promise equals global promise
- 00:17:52 to use the default nodejs promise
- 00:17:54 implementation instead of the Mongoose
- 00:17:56 one and with that if you restart the
- 00:17:58 server you shouldn't get this anymore so
- 00:18:00 now if you again start sending your
- 00:18:03 requests and so on it should still work
- 00:18:06 as before but you shouldn't get this
- 00:18:08 deprecation warning now feel free to
- 00:18:10 find you this more to adjust it to your
- 00:18:13 needs and requirements I'm happy with
- 00:18:15 the current state and I'd say in the
- 00:18:17 next video we take a closer look at
- 00:18:19 further evolving our data structures and
- 00:18:22 also adding some orders and making sure
- 00:18:27 that we save these in the database too