Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
We are going to wrap up the API and tests! You got this!
This video doesn't have any notes.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
>> So, let's keep sticking
with our reviews review.
0:00
Let's kick out our ability to
add a new review to a course.
0:03
Now, it'll have a dynamic ID.
0:06
So, what we'll need to do here is
capture the correct HTTP method right.
0:08
What should that look like?
0:13
Go ahead.
0:14
You give it a try.
0:15
You've got this.
0:16
Now pause me and
come back when you're all done.
0:17
Ready?
0:21
Well, it's a post.
0:21
So we're gonna say,
post courses the courseId and
0:23
reviews, cuz we're gonna post
a new review to a certain course.
0:28
And of course, that is "application/json".
0:35
I'm gonna close this.
0:40
This get longer,
the longer these things get.
0:41
So we're gonna do a request and
a response, we're gonna return null.
0:44
So it knows that we're talking
about the right method there and
0:50
let's just go ahead and get our
gson::toJson) in here and semicolon there.
0:56
So first, we wanna get the courseId off.
1:04
So, we're gonna do Integer.parseInt and
1:08
we're gonna do req.params and
we're gonna pull off ("courseId").
1:12
So now,
we know what course they're talking about.
1:18
We're gonna build a new review and
we're gonna to pull gson.fromJson.
1:23
We're gonna get the body and we're gonna
pump that into a new Review.class.
1:29
Now the thing is here,
the body there does not have the ID.
1:36
So we actually need to
set that afterwards,
1:41
that was kinda the tricky one on this.
1:43
So now that the review is all set up,
we can add it, but
1:47
we probably should try to
catch the Dao exception.
1:51
So, let's do it in a try.
1:56
Cuz remember,
1:58
this is where we had the problem of
the foreign key not being in place.
1:59
So the foreign key,
if the course didn't exist, it blew up.
2:04
It threw one of these exceptions.
2:12
So, let's go ahead and
let's... let's bring this across.
2:13
This is also the first time that
we are using the review Dao so,
2:20
we need to make one of those right.
2:23
So, here we go.
2:24
So just like the course Dao,
we're gonna have a ReviewDao reviewDao and
2:27
it's gonna be a new Sql2oReviewDao
that implementation and
2:31
we're also going to pass on
that same sql2o instance.
2:36
Here we go.
2:41
Cool.
2:42
So, we're gonna catch that error and
what do you think we should do with it.
2:44
Now just in case they
are trying to add a review,
2:48
I think we should provably throw
an API error, so they can see it.
2:50
So we'll say, throw new ApiError and
that's a 500 and
2:54
we'll get the message back from that,
2:59
cuz it's the Dao exception
we made that pretty.
3:03
And if that worked,
we wanna set the status.
3:11
We wanna say, (201) or created and
3:14
we will return new review,
cuz review will have the ID.
3:18
So, let's go ahead and
let's make sure this works with Postman.
3:25
So, let's go over here.
3:28
Let's see what courses
we have available first.
3:29
I forgot to start my server.
3:34
So, let's come back here.
3:36
So we're gonna run the API,
spark has ignited.
3:40
And now if I come over here and I try to
get a look at what these courses are and
3:44
I send them, we got a couple.
3:49
So let's go ahead and let's do for this
number two here, this REST API basics.
3:51
We'll do a new post to courses, 2 which is
3:57
the REST API basics and
we're gonna add a new review.
4:02
So, it is going to have.
4:08
We're going to set the header.
4:14
Oops, [LAUGH] in the body
of the other one.
4:16
So, we're gonna set the header here.
4:21
And in the body here, again,
we're gonna do raw and
4:23
let's go ahead and I really enjoyed
that course that Kenneth did.
4:27
So we're gonna say, "rating": 5 and
then we're gonna have in here
4:32
there's a "comment": and this is
a very typical review from Kenneth.
4:37
"Kenneth has an amazing beard".
4:43
Which is very true and
4:46
I'm glad that people like to
point that out all the time.
4:47
So, please let him know that
he has an amazing beard.
4:50
Tweet at him or something.
4:52
So, I'm gonna post here.
4:53
Let's see what we got back.
4:56
Awesome.
We got a review back, and
4:57
see it has its own ID up here.
4:59
Here's the review, the rating, did it.
5:01
So now, can you write the rest method
that will return all reviews for
5:05
a given course?
5:11
It too is gonna need a dynamic URL,
now pause me.
5:12
Make it happen.
5:14
Ready?
5:18
Did you get it?
5:19
Here's what I did.
5:20
So, I made a new get method and it looks
very similar to what we had up there.
5:21
It's a courses with a courseId and
5:27
then we're gonna do reviews and
5:31
it's gonna be application json, and
5:35
we're going to have a req, and a res,
5:40
and it's gonna be gson toJson.
5:45
I want to return null,
just so it gets happy here.
5:49
So this says, get all of the courses.
5:56
So we're gonna say, int courseId
5:59
= Integer.parseInt(req.params("courseId")).
6:03
Then we're just gonna simply return
reviewDao.findByCourseId and
6:12
we pop in that courseId that
we that we just got pretty nice,
6:17
and handy method there, right?
6:22
Great.
We got it.
6:26
So, time to write some functional test.
6:26
So let's write a functional
test that make sure that when
6:29
we add a new review that it
returns the proper status code.
6:33
Give it a go and then pause,
and I'll show you what I did.
6:37
How did you do?
6:43
So I'm gonna flip over to the API test,
6:44
we're gonna make a new test here and
6:49
let's call it
addingReviewGivesCreatedStatus.
6:53
It's similar to the course
one we did before.
6:59
So we're gonna say, Map and
it's gonna be a string with Objects,
7:01
cuz I'm gonna make another
one of these HashMaps,
7:07
cuz I don't like to generate Json
myself anymore in its old age.
7:11
Values.put and
we're gonna put in there rating and
7:16
because we've put that second thing to be
an object, we can just pop a 5 in there.
7:17
And we'll say, values.put("comment"),
7:19
then we'll just do "Test comment"
7:27
And now we are going
to do Api response and
7:39
we're gonna call the Api and
we're gonna push
7:43
through a "POST" and
we're gonna say, String.
7:49
Now, we're not gonna call the Api.
7:55
We're gonna do client.request and
7:58
we're gonna do String.format.
8:03
And what we want to push it to is what we
just built that courses/%d/reviews and
8:06
we will pass in to our formatter there,
we're gonna put in the course.
8:14
That's there, .getID.
8:22
We need to make a course too up here.
8:27
I say, Course course = newTestCourse.
8:33
We'll add that.
8:39
New HashMap and here we go.
8:48
So we're gonna post,
8:51
we're gonna post to that URL and
8:55
we're also gonna give a body
9:01
here of gson.toJson values.
9:06
What is it complaining about?
9:12
ApiResponse.
9:16
What am I doing?
9:17
There we go.
9:19
So, we now have a response and we will
just make sure that we get back a 200.
9:21
Now we just saw that this
worked in Postman, but
9:25
by writing this test it
will always be true.
9:29
So this test can run every time we
run our tests, that's what we want.
9:32
Let's go ahead and
run our test not our Api.
9:36
Let's run the Api instead of the test.
9:42
So they're all in course-reviews
on this and boom, we got it.
9:45
The new ApiTest here,
added review gets created status.
9:50
Awesome.
9:53
And now, we need to make sure
that we send the correct error
9:53
when the course doesn't exist.
9:56
Remember that this is an exception.
9:58
We need to make sure that
this is the 500 error.
9:59
So, let's go ahead and
we will just take this part of the test.
10:02
And make a new test, and we'll just
make sure that there's no course.
10:12
And we'll just make up the course number.
10:15
Oops, so I'm gonna make a new test and
10:18
we're gonna call this
addingReviewToUnknownCourseThrowsError.
10:23
Wait, I'm just wanna make
sure that we have that.
10:32
So, I'm gonna paste there
what I copied before.
10:33
So instead of posting, we're gonna
post to just 42 here and we don't
10:36
need to do a string format anymore,
because we don't have an actual course.
10:41
Then instead of returning a 201,
we want this thing to return a 500.
10:47
We wanna make sure that the error happens.
10:51
So we'll save that and we'll run that and
10:55
I have an extra parenth there.
11:00
I have an extra parenth here and
I'm missing one here.
11:04
There we go.
11:07
Awesome, works.
11:10
And now, do you think you can kick
out to get by course ID call?
11:12
So, we wanna make sure that we can find
multiple reviews for one single course.
11:16
So make sure that you add a few reviews
in the test and you can make an array of
11:20
reviews, it doesn't need to be an array
list, with what gets returned, but
11:24
then you wanna make sure there's at
least that same number of them so
11:27
kick out a couple of reviews.
11:31
Add them to a course and
see if you can get it back.
11:32
Might be a little bit tricky around
the gson thing, but don't be afraid.
11:35
Go for it.
11:39
Ready?
11:43
Here's what I did.
11:44
So I made a new test and it's called
11:45
multipleReviewsReturnedForCourse, and
11:50
what we're gonna do is we're gonna get
11:56
a course equals the newTestCourse,
12:01
and we will add that
course to our courseDao,
12:06
and then we will create
a couple inline reviews here.
12:12
So we'll say, reviewDao,
which I guess we forgot to add up here,
12:20
cuz we haven't needed it yet.
12:25
So, we will make a new reviewDao
12:28
= new Sql2oReviewDao(sql2o) and
12:33
we will make this be a field.
12:39
Yep, we'll come back to our course here.
12:43
So, we'll add a new review and
12:48
it's going to have course.get
12:52
Id() and we'll do 5.
12:58
We'll do Test comment 1 and
then let's the same thing and
13:02
we'll say another 1 and we'll add it and
13:07
it's gotta 4 and it's Test comment 2.
13:11
So now, we're gonna get a response back.
13:15
ApiResponse = client.request and
13:18
we are going to do a "GET",
13:22
we'll do a String.format on "/courses/%d/",
13:25
cuz it's a number, /reviews.
13:31
Drop this down a line, so
we have more space and
13:38
I'm gonna pass in here
the course.getId for the format.
13:41
And then finally, we're doing a GET,
so we don't need a body.
13:46
So we wanna pull back an array,
this works.
13:51
So if you can do a Review[]
array of reviews =
13:55
gson.fromJson(res.getBody()), so
we got the JSON there and
14:00
we will pump that into an array
of a class of array of reviews.
14:07
Kinda cool and then we're gonna
make sure there are two of them.
14:13
You might have looked at
the gson documentation.
14:20
You can also pump that
in to an array list, but
14:22
we didn't need an array list here.
14:24
We just needed to see that there were two.
14:25
So, I'm gonna run that.
14:28
We got it, awesome.
14:31
So, we've basically done it.
14:33
We've implemented the reviews Api to
the same level that we did the courses.
14:34
Now we could, of course,
support deleting and authentication and
14:38
maybe some sort of roll
up on the main course.
14:42
Like we could say,
14:44
the total number reviews when you first
look at the course or we could say,
14:45
the average review for this, but
that's just bells and whistles from here.
14:48
You have the basics,
you could build all of that.
14:52
I've added some directions for
you to explore in the teachers's notes and
14:54
great job on reviewing this.
14:59
I hope that,
15:00
that review of reviews gives you a preview
of what your future purview may hold.
15:01
How did you do at the review of reviews?
15:07
Did you have to look in
your rear view mirror?
15:09
Or did your preview enhance your view?
15:11
I'll stop.
15:14
But seriously, if anything isn't sticking
or making sense, please, please, please,
15:15
bring it to the community.
15:18
We'll work it out.
15:19
Everyone benefits from questions and
talking about this stuff.
15:21
It's what happens all
the time in the workplace.
15:24
You just like lean over and
go something like this.
15:26
Hey, Carlene.
15:29
Do you know why Kenneth
used the post right here?
15:30
>> It looks like he was creating
a new resource, that's a 201.
15:32
>> [LAUGH] That's right there.
15:36
Thanks.
15:38
Nice hadouken, by the way.
15:39
It happens all the time,
you lean on each other like that.
15:44
It's what community is all about,
you are not alone.
15:46
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up