1 00:00:00,317 --> 00:00:03,577 >> So, let's keep sticking with our reviews review. 2 00:00:03,577 --> 00:00:06,497 Let's kick out our ability to add a new review to a course. 3 00:00:06,497 --> 00:00:08,137 Now, it'll have a dynamic ID. 4 00:00:08,137 --> 00:00:13,257 So, what we'll need to do here is capture the correct HTTP method right. 5 00:00:13,257 --> 00:00:14,637 What should that look like? 6 00:00:14,637 --> 00:00:15,257 Go ahead. 7 00:00:15,257 --> 00:00:16,357 You give it a try. 8 00:00:16,357 --> 00:00:17,277 You've got this. 9 00:00:17,277 --> 00:00:21,417 Now pause me and come back when you're all done. 10 00:00:21,417 --> 00:00:21,996 Ready? 11 00:00:21,996 --> 00:00:23,457 Well, it's a post. 12 00:00:23,457 --> 00:00:28,504 So we're gonna say, post courses the courseId and 13 00:00:28,504 --> 00:00:35,127 reviews, cuz we're gonna post a new review to a certain course. 14 00:00:35,127 --> 00:00:40,127 And of course, that is "application/json". 15 00:00:40,127 --> 00:00:41,886 I'm gonna close this. 16 00:00:41,886 --> 00:00:44,028 This get longer, the longer these things get. 17 00:00:44,028 --> 00:00:50,566 So we're gonna do a request and a response, we're gonna return null. 18 00:00:50,566 --> 00:00:56,775 So it knows that we're talking about the right method there and 19 00:00:56,775 --> 00:01:04,637 let's just go ahead and get our gson::toJson) in here and semicolon there. 20 00:01:04,637 --> 00:01:08,046 So first, we wanna get the courseId off. 21 00:01:08,046 --> 00:01:12,090 So, we're gonna do Integer.parseInt and 22 00:01:12,090 --> 00:01:18,987 we're gonna do req.params and we're gonna pull off ("courseId"). 23 00:01:18,987 --> 00:01:23,377 So now, we know what course they're talking about. 24 00:01:23,377 --> 00:01:29,510 We're gonna build a new review and we're gonna to pull gson.fromJson. 25 00:01:29,510 --> 00:01:36,576 We're gonna get the body and we're gonna pump that into a new Review.class. 26 00:01:36,576 --> 00:01:41,256 Now the thing is here, the body there does not have the ID. 27 00:01:41,256 --> 00:01:43,465 So we actually need to set that afterwards, 28 00:01:43,465 --> 00:01:45,386 that was kinda the tricky one on this. 29 00:01:47,727 --> 00:01:51,759 So now that the review is all set up, we can add it, but 30 00:01:51,759 --> 00:01:56,330 we probably should try to catch the Dao exception. 31 00:01:56,330 --> 00:01:58,417 So, let's do it in a try. 32 00:01:58,417 --> 00:01:59,597 Cuz remember, 33 00:01:59,597 --> 00:02:04,870 this is where we had the problem of the foreign key not being in place. 34 00:02:04,870 --> 00:02:12,496 So the foreign key, if the course didn't exist, it blew up. 35 00:02:12,496 --> 00:02:13,850 It threw one of these exceptions. 36 00:02:13,850 --> 00:02:20,480 So, let's go ahead and let's... let's bring this across. 37 00:02:20,480 --> 00:02:23,214 This is also the first time that we are using the review Dao so, 38 00:02:23,214 --> 00:02:24,850 we need to make one of those right. 39 00:02:24,850 --> 00:02:27,002 So, here we go. 40 00:02:27,002 --> 00:02:31,892 So just like the course Dao, we're gonna have a ReviewDao reviewDao and 41 00:02:31,892 --> 00:02:36,063 it's gonna be a new Sql2oReviewDao that implementation and 42 00:02:36,063 --> 00:02:41,080 we're also going to pass on that same sql2o instance. 43 00:02:41,080 --> 00:02:42,307 Here we go. 44 00:02:42,307 --> 00:02:44,146 Cool. 45 00:02:44,146 --> 00:02:48,237 So, we're gonna catch that error and what do you think we should do with it. 46 00:02:48,237 --> 00:02:50,695 Now just in case they are trying to add a review, 47 00:02:50,695 --> 00:02:54,084 I think we should provably throw an API error, so they can see it. 48 00:02:54,084 --> 00:02:59,920 So we'll say, throw new ApiError and that's a 500 and 49 00:02:59,920 --> 00:03:03,849 we'll get the message back from that, 50 00:03:03,849 --> 00:03:08,750 cuz it's the Dao exception we made that pretty. 51 00:03:11,960 --> 00:03:14,499 And if that worked, we wanna set the status. 52 00:03:14,499 --> 00:03:18,163 We wanna say, (201) or created and 53 00:03:18,163 --> 00:03:23,240 we will return new review, cuz review will have the ID. 54 00:03:25,020 --> 00:03:28,256 So, let's go ahead and let's make sure this works with Postman. 55 00:03:28,256 --> 00:03:29,407 So, let's go over here. 56 00:03:29,407 --> 00:03:31,820 Let's see what courses we have available first. 57 00:03:34,218 --> 00:03:36,307 I forgot to start my server. 58 00:03:36,307 --> 00:03:37,627 So, let's come back here. 59 00:03:40,126 --> 00:03:44,200 So we're gonna run the API, spark has ignited. 60 00:03:44,200 --> 00:03:49,567 And now if I come over here and I try to get a look at what these courses are and 61 00:03:49,567 --> 00:03:51,746 I send them, we got a couple. 62 00:03:51,746 --> 00:03:57,990 So let's go ahead and let's do for this number two here, this REST API basics. 63 00:03:57,990 --> 00:04:02,547 We'll do a new post to courses, 2 which is 64 00:04:02,547 --> 00:04:08,256 the REST API basics and we're gonna add a new review. 65 00:04:08,256 --> 00:04:11,640 So, it is going to have. 66 00:04:14,517 --> 00:04:16,722 We're going to set the header. 67 00:04:16,722 --> 00:04:21,136 Oops, [LAUGH] in the body of the other one. 68 00:04:21,136 --> 00:04:23,200 So, we're gonna set the header here. 69 00:04:23,200 --> 00:04:27,248 And in the body here, again, we're gonna do raw and 70 00:04:27,248 --> 00:04:32,407 let's go ahead and I really enjoyed that course that Kenneth did. 71 00:04:32,407 --> 00:04:37,611 So we're gonna say, "rating": 5 and then we're gonna have in here 72 00:04:37,611 --> 00:04:43,007 there's a "comment": and this is a very typical review from Kenneth. 73 00:04:43,007 --> 00:04:46,427 "Kenneth has an amazing beard". 74 00:04:46,427 --> 00:04:47,494 Which is very true and 75 00:04:47,494 --> 00:04:50,890 I'm glad that people like to point that out all the time. 76 00:04:50,890 --> 00:04:52,667 So, please let him know that he has an amazing beard. 77 00:04:52,667 --> 00:04:53,867 Tweet at him or something. 78 00:04:53,867 --> 00:04:56,746 So, I'm gonna post here. 79 00:04:56,746 --> 00:04:57,987 Let's see what we got back. 80 00:04:57,987 --> 00:04:59,788 Awesome. We got a review back, and 81 00:04:59,788 --> 00:05:01,280 see it has its own ID up here. 82 00:05:01,280 --> 00:05:05,356 Here's the review, the rating, did it. 83 00:05:05,356 --> 00:05:11,065 So now, can you write the rest method that will return all reviews for 84 00:05:11,065 --> 00:05:12,590 a given course? 85 00:05:12,590 --> 00:05:14,997 It too is gonna need a dynamic URL, now pause me. 86 00:05:14,997 --> 00:05:15,996 Make it happen. 87 00:05:18,716 --> 00:05:19,497 Ready? 88 00:05:19,497 --> 00:05:20,637 Did you get it? 89 00:05:20,637 --> 00:05:21,896 Here's what I did. 90 00:05:21,896 --> 00:05:27,290 So, I made a new get method and it looks very similar to what we had up there. 91 00:05:27,290 --> 00:05:31,588 It's a courses with a courseId and 92 00:05:31,588 --> 00:05:35,589 then we're gonna do reviews and 93 00:05:35,589 --> 00:05:40,331 it's gonna be application json, and 94 00:05:40,331 --> 00:05:45,070 we're going to have a req, and a res, 95 00:05:45,070 --> 00:05:49,091 and it's gonna be gson toJson. 96 00:05:49,091 --> 00:05:51,009 I want to return null, just so it gets happy here. 97 00:05:56,706 --> 00:05:59,090 So this says, get all of the courses. 98 00:05:59,090 --> 00:06:03,676 So we're gonna say, int courseId 99 00:06:03,676 --> 00:06:12,226 = Integer.parseInt(req.params("courseId")). 100 00:06:12,226 --> 00:06:17,793 Then we're just gonna simply return reviewDao.findByCourseId and 101 00:06:17,793 --> 00:06:22,599 we pop in that courseId that we that we just got pretty nice, 102 00:06:22,599 --> 00:06:25,160 and handy method there, right? 103 00:06:26,247 --> 00:06:26,777 Great. We got it. 104 00:06:26,777 --> 00:06:29,760 So, time to write some functional test. 105 00:06:29,760 --> 00:06:33,710 So let's write a functional test that make sure that when 106 00:06:33,710 --> 00:06:37,757 we add a new review that it returns the proper status code. 107 00:06:37,757 --> 00:06:40,460 Give it a go and then pause, and I'll show you what I did. 108 00:06:43,047 --> 00:06:44,587 How did you do? 109 00:06:44,587 --> 00:06:49,113 So I'm gonna flip over to the API test, 110 00:06:49,113 --> 00:06:53,228 we're gonna make a new test here and 111 00:06:53,228 --> 00:06:59,030 let's call it addingReviewGivesCreatedStatus. 112 00:06:59,030 --> 00:07:01,846 It's similar to the course one we did before. 113 00:07:01,846 --> 00:07:07,295 So we're gonna say, Map and it's gonna be a string with Objects, 114 00:07:07,295 --> 00:07:11,480 cuz I'm gonna make another one of these HashMaps, 115 00:07:11,480 --> 00:07:16,761 cuz I don't like to generate Json myself anymore in its old age. 116 00:07:16,761 --> 00:07:17,745 Values.put and we're gonna put in there rating and 117 00:07:17,745 --> 00:07:19,301 because we've put that second thing to be an object, we can just pop a 5 in there. 118 00:07:19,301 --> 00:07:27,707 And we'll say, values.put("comment"), 119 00:07:27,707 --> 00:07:33,916 then we'll just do "Test comment" 120 00:07:39,200 --> 00:07:43,868 And now we are going to do Api response and 121 00:07:43,868 --> 00:07:49,224 we're gonna call the Api and we're gonna push 122 00:07:49,224 --> 00:07:55,147 through a "POST" and we're gonna say, String. 123 00:07:55,147 --> 00:07:58,924 Now, we're not gonna call the Api. 124 00:07:58,924 --> 00:08:03,052 We're gonna do client.request and 125 00:08:03,052 --> 00:08:06,917 we're gonna do String.format. 126 00:08:06,917 --> 00:08:14,786 And what we want to push it to is what we just built that courses/%d/reviews and 127 00:08:14,786 --> 00:08:22,580 we will pass in to our formatter there, we're gonna put in the course. 128 00:08:22,580 --> 00:08:27,737 That's there, .getID. 129 00:08:27,737 --> 00:08:30,940 We need to make a course too up here. 130 00:08:33,607 --> 00:08:38,120 I say, Course course = newTestCourse. 131 00:08:39,760 --> 00:08:40,260 We'll add that. 132 00:08:48,549 --> 00:08:51,776 New HashMap and here we go. 133 00:08:51,776 --> 00:08:55,845 So we're gonna post, 134 00:08:55,845 --> 00:09:01,627 we're gonna post to that URL and 135 00:09:01,627 --> 00:09:06,768 we're also gonna give a body 136 00:09:06,768 --> 00:09:12,347 here of gson.toJson values. 137 00:09:12,347 --> 00:09:13,780 What is it complaining about? 138 00:09:16,180 --> 00:09:17,906 ApiResponse. 139 00:09:17,906 --> 00:09:19,467 What am I doing? 140 00:09:19,467 --> 00:09:21,186 There we go. 141 00:09:21,186 --> 00:09:25,820 So, we now have a response and we will just make sure that we get back a 200. 142 00:09:25,820 --> 00:09:29,198 Now we just saw that this worked in Postman, but 143 00:09:29,198 --> 00:09:32,327 by writing this test it will always be true. 144 00:09:32,327 --> 00:09:36,267 So this test can run every time we run our tests, that's what we want. 145 00:09:36,267 --> 00:09:39,257 Let's go ahead and run our test not our Api. 146 00:09:42,136 --> 00:09:45,346 Let's run the Api instead of the test. 147 00:09:45,346 --> 00:09:50,197 So they're all in course-reviews on this and boom, we got it. 148 00:09:50,197 --> 00:09:53,076 The new ApiTest here, added review gets created status. 149 00:09:53,076 --> 00:09:53,976 Awesome. 150 00:09:53,976 --> 00:09:56,644 And now, we need to make sure that we send the correct error 151 00:09:56,644 --> 00:09:58,176 when the course doesn't exist. 152 00:09:58,176 --> 00:09:59,917 Remember that this is an exception. 153 00:09:59,917 --> 00:10:02,597 We need to make sure that this is the 500 error. 154 00:10:02,597 --> 00:10:07,522 So, let's go ahead and we will just take this part of the test. 155 00:10:12,726 --> 00:10:15,467 And make a new test, and we'll just make sure that there's no course. 156 00:10:15,467 --> 00:10:16,980 And we'll just make up the course number. 157 00:10:18,820 --> 00:10:23,642 Oops, so I'm gonna make a new test and 158 00:10:23,642 --> 00:10:32,557 we're gonna call this addingReviewToUnknownCourseThrowsError. 159 00:10:32,557 --> 00:10:33,915 Wait, I'm just wanna make sure that we have that. 160 00:10:33,915 --> 00:10:36,017 So, I'm gonna paste there what I copied before. 161 00:10:36,017 --> 00:10:41,325 So instead of posting, we're gonna post to just 42 here and we don't 162 00:10:41,325 --> 00:10:47,086 need to do a string format anymore, because we don't have an actual course. 163 00:10:47,086 --> 00:10:51,527 Then instead of returning a 201, we want this thing to return a 500. 164 00:10:51,527 --> 00:10:54,080 We wanna make sure that the error happens. 165 00:10:55,160 --> 00:11:00,620 So we'll save that and we'll run that and 166 00:11:00,620 --> 00:11:04,889 I have an extra parenth there. 167 00:11:04,889 --> 00:11:07,490 I have an extra parenth here and I'm missing one here. 168 00:11:07,490 --> 00:11:10,417 There we go. 169 00:11:10,417 --> 00:11:12,397 Awesome, works. 170 00:11:12,397 --> 00:11:16,280 And now, do you think you can kick out to get by course ID call? 171 00:11:16,280 --> 00:11:20,996 So, we wanna make sure that we can find multiple reviews for one single course. 172 00:11:20,996 --> 00:11:24,433 So make sure that you add a few reviews in the test and you can make an array of 173 00:11:24,433 --> 00:11:27,873 reviews, it doesn't need to be an array list, with what gets returned, but 174 00:11:27,873 --> 00:11:31,035 then you wanna make sure there's at least that same number of them so 175 00:11:31,035 --> 00:11:32,447 kick out a couple of reviews. 176 00:11:32,447 --> 00:11:34,520 Add them to a course and see if you can get it back. 177 00:11:35,750 --> 00:11:39,867 Might be a little bit tricky around the gson thing, but don't be afraid. 178 00:11:39,867 --> 00:11:40,807 Go for it. 179 00:11:43,246 --> 00:11:44,027 Ready? 180 00:11:44,027 --> 00:11:45,786 Here's what I did. 181 00:11:45,786 --> 00:11:50,475 So I made a new test and it's called 182 00:11:50,475 --> 00:11:56,463 multipleReviewsReturnedForCourse, and 183 00:11:56,463 --> 00:12:01,801 what we're gonna do is we're gonna get 184 00:12:01,801 --> 00:12:06,816 a course equals the newTestCourse, 185 00:12:06,816 --> 00:12:12,962 and we will add that course to our courseDao, 186 00:12:12,962 --> 00:12:20,270 and then we will create a couple inline reviews here. 187 00:12:20,270 --> 00:12:25,616 So we'll say, reviewDao, which I guess we forgot to add up here, 188 00:12:25,616 --> 00:12:28,107 cuz we haven't needed it yet. 189 00:12:28,107 --> 00:12:33,129 So, we will make a new reviewDao 190 00:12:33,129 --> 00:12:39,269 = new Sql2oReviewDao(sql2o) and 191 00:12:39,269 --> 00:12:43,740 we will make this be a field. 192 00:12:43,740 --> 00:12:48,187 Yep, we'll come back to our course here. 193 00:12:48,187 --> 00:12:52,921 So, we'll add a new review and 194 00:12:52,921 --> 00:12:58,205 it's going to have course.get 195 00:12:58,205 --> 00:13:02,040 Id() and we'll do 5. 196 00:13:02,040 --> 00:13:07,683 We'll do Test comment 1 and then let's the same thing and 197 00:13:07,683 --> 00:13:11,712 we'll say another 1 and we'll add it and 198 00:13:11,712 --> 00:13:15,647 it's gotta 4 and it's Test comment 2. 199 00:13:15,647 --> 00:13:18,226 So now, we're gonna get a response back. 200 00:13:18,226 --> 00:13:22,588 ApiResponse = client.request and 201 00:13:22,588 --> 00:13:25,961 we are going to do a "GET", 202 00:13:25,961 --> 00:13:31,165 we'll do a String.format on "/courses/%d/", 203 00:13:31,165 --> 00:13:35,116 cuz it's a number, /reviews. 204 00:13:38,340 --> 00:13:41,780 Drop this down a line, so we have more space and 205 00:13:41,780 --> 00:13:46,117 I'm gonna pass in here the course.getId for the format. 206 00:13:46,117 --> 00:13:50,380 And then finally, we're doing a GET, so we don't need a body. 207 00:13:51,500 --> 00:13:55,196 So we wanna pull back an array, this works. 208 00:13:55,196 --> 00:14:00,050 So if you can do a Review[] array of reviews = 209 00:14:00,050 --> 00:14:07,147 gson.fromJson(res.getBody()), so we got the JSON there and 210 00:14:07,147 --> 00:14:13,533 we will pump that into an array of a class of array of reviews. 211 00:14:13,533 --> 00:14:17,802 Kinda cool and then we're gonna make sure there are two of them. 212 00:14:20,560 --> 00:14:22,446 You might have looked at the gson documentation. 213 00:14:22,446 --> 00:14:24,422 You can also pump that in to an array list, but 214 00:14:24,422 --> 00:14:25,987 we didn't need an array list here. 215 00:14:25,987 --> 00:14:27,470 We just needed to see that there were two. 216 00:14:28,570 --> 00:14:29,240 So, I'm gonna run that. 217 00:14:31,550 --> 00:14:33,357 We got it, awesome. 218 00:14:33,357 --> 00:14:34,936 So, we've basically done it. 219 00:14:34,936 --> 00:14:38,926 We've implemented the reviews Api to the same level that we did the courses. 220 00:14:38,926 --> 00:14:42,505 Now we could, of course, support deleting and authentication and 221 00:14:42,505 --> 00:14:44,907 maybe some sort of roll up on the main course. 222 00:14:44,907 --> 00:14:45,740 Like we could say, 223 00:14:45,740 --> 00:14:48,970 the total number reviews when you first look at the course or we could say, 224 00:14:48,970 --> 00:14:52,376 the average review for this, but that's just bells and whistles from here. 225 00:14:52,376 --> 00:14:54,837 You have the basics, you could build all of that. 226 00:14:54,837 --> 00:14:59,105 I've added some directions for you to explore in the teachers's notes and 227 00:14:59,105 --> 00:15:00,806 great job on reviewing this. 228 00:15:00,806 --> 00:15:01,746 I hope that, 229 00:15:01,746 --> 00:15:07,487 that review of reviews gives you a preview of what your future purview may hold. 230 00:15:07,487 --> 00:15:09,127 How did you do at the review of reviews? 231 00:15:09,127 --> 00:15:11,487 Did you have to look in your rear view mirror? 232 00:15:11,487 --> 00:15:14,087 Or did your preview enhance your view? 233 00:15:14,087 --> 00:15:15,167 I'll stop. 234 00:15:15,167 --> 00:15:18,795 But seriously, if anything isn't sticking or making sense, please, please, please, 235 00:15:18,795 --> 00:15:19,887 bring it to the community. 236 00:15:19,887 --> 00:15:21,310 We'll work it out. 237 00:15:21,310 --> 00:15:24,187 Everyone benefits from questions and talking about this stuff. 238 00:15:24,187 --> 00:15:26,007 It's what happens all the time in the workplace. 239 00:15:26,007 --> 00:15:29,767 You just like lean over and go something like this. 240 00:15:29,767 --> 00:15:30,906 Hey, Carlene. 241 00:15:30,906 --> 00:15:32,866 Do you know why Kenneth used the post right here? 242 00:15:32,866 --> 00:15:36,886 >> It looks like he was creating a new resource, that's a 201. 243 00:15:36,886 --> 00:15:38,811 >> [LAUGH] That's right there. 244 00:15:38,811 --> 00:15:39,452 Thanks. 245 00:15:39,452 --> 00:15:44,372 Nice hadouken, by the way. 246 00:15:44,372 --> 00:15:46,952 It happens all the time, you lean on each other like that. 247 00:15:46,952 --> 00:15:49,700 It's what community is all about, you are not alone.