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
Let's automatically set the reviewer on the creation of new reviewers to the logged in users. We will use an annotated event handler to capture the BeforeCreateEvent.
So we have a nicety that
we'd like to add to our API.
0:00
We want the creator of
the review resource to be set
0:03
as the reviewer when it's created.
0:06
This idea of running certain code at
certain times is pretty common request.
0:09
As you can imagine it's usually
where the business logic lives and
0:12
since all the controller code is
currently tucked away out of sight,
0:16
it might be a little confusing as to
where we should add logic like this.
0:19
Well the good news is that this
problem has been thought about and
0:23
it has been solved for you.
0:26
Probably, there are eight events
that the spring data rest emits.
0:27
These are pretty self-explanatory and
0:31
knowing what you can hook into that
will probably make you feel a lot more
0:33
comfortable about not having
access to those controllers.
0:37
This is usually where you'd
write any custom logic, right?
0:40
So we want to set the reviewer
before things are created.
0:44
So we'll use the before create event.
0:47
Let's do this.
0:49
There are a few ways to register events.
0:51
If you wanna capture all entity creation
you can write an application listener.
0:53
But in our example we're really only
concerned with when reviews are created.
0:56
What we're going to do is
write an annotated handler.
1:01
Which we can restrict to
a review entity specifically.
1:04
So in our review package, let's make
a new class named ReviewEventHandler.
1:07
New Java class ReviewEventHandler.
1:16
Okay and now we'll annotate that
with RepositoryEventHandler.
1:24
And with that does is
that takes a class and
1:34
it's whatever we're interested in watching
which remember that's Review.class.
1:37
So the way that these work is you
define what it is that you're
1:41
trying to do in a descriptive method,
right.
1:44
So let's go ahead and let's say.
1:46
We're trying to do is we're trying to
add the reviewer as it goes, right.
1:49
So let's say public void
addReviewerBasedOnLoggedInUser.
1:51
It can be as descriptive as you want.
1:59
So we'll say review review and
we want this to happen before, right?
2:01
So we're going to do handle before create.
2:09
So having these as separate methods is
pretty nice because each of them are right
2:17
for unit testing right.
2:22
Okay so let's inject our user repository
so we can get stuff out of it, so
2:24
we'll say private final UserRepository,
2:28
so users, and
I'm gonna go ahead and allow this.
2:33
With this automatically add
a constructor parameter and
2:39
then we'll mark our
constructor here as auto wired.
2:43
And because we need to have this
picked up by a component scan,
2:50
we need to mark it as a component.
2:53
And now let's work our magic.
2:56
So, to get the currently long
in user you do this incantation.
2:58
So let's say get user name and
that's from security ContextHolder
3:02
has a getContext, I'll go ahead and
give us some space.
3:10
Has a getContext, and
then it has a getAuthentication,
3:16
and then it has a getName.
3:22
Note that we're going to get a null
pointer exception here if they aren't
3:26
authenticated.
3:28
But alas, they should be so
we'll go grab our user.
3:29
So we'll say user user =
users.findByUserName and
3:33
we'll pass in that username.
3:40
And finally,
we'll just set it on the reviewer and
3:50
the review will say
setReviewer[user] makes sense right?
3:54
Before things are created, okay?
3:59
I will go and reboot our server here.
4:00
Let's see, let's grab somebody
over here to make a review for,
4:06
let's see, let's grab Seth Kroger.
4:12
He is an amazing moderator for us so
let's write an appropriate one for him.
4:14
So we're going to make this a post and
we're going to erase this one and
4:20
we're gonna go to the authorization
we're gonna log in actually as Seth,
4:24
he's got the same password
which is password.
4:27
Seth change that,
say update request, okay.
4:30
And if we come over here to the body,
this is actually a review.
4:33
So what we wanna do is we're
gonna have him give us
4:39
a little bit of a harsh rating.
4:42
Let's say the rating.
4:43
Let's do the course first.
4:45
So "course" and
now again we've moved this.
4:48
So it's "/api/v1 Courses one so
4:54
basics and
we're going to give a rating of two.
4:59
That's pretty harsh stuff,
which what, what's he upset about?
5:02
What is Seth upset about?
5:06
Let's see.
5:07
So for the description come here and
5:10
say why why did you use
5:17
system.io.console.
5:22
Well that's a lot isolation points so
I have to calm down.
5:27
Do you know how many
times I've had to answer
5:30
why this doesn't work in the clip.
5:36
I totally made that up, that's
something Seth would never ever say.
5:41
He's one of those amazing moderators
that makes everyone feel so
5:45
comfortable in the community and thanks
for keeping something so positive and
5:48
being so patient that the students and
I really appreciate it.
5:51
Okay let's see if this works.
5:54
So we have not set the reviewer,
but Seth is logged in, and
5:56
we're going to click send.
6:00
Here we go.
We got a bad request because,
6:02
why did we get bad request?
6:07
No suitable found to read
the request body to object.
6:09
Do I have a weird header?
6:15
I did not set this.
6:19
I said it as text that
something good to know, right.
6:21
So doesn't know it says and
it says right here.
6:23
Can't do with the content type plaintext,
right?
6:25
Let's switch this over to my
application JSON and they set there.
6:27
Maybe that will be an answer for
this one isn't better there in the video.
6:33
So that's maybe one you
don't have to answer.
6:36
Boom, there it is and
here comes Seth Kroger coming across.
6:39
So as you can imagine, we could do all
sorts of other handling in these events,
6:43
including sending notifications,
updating caches, some advance validation.
6:46
But whatever business logic you
can dream up you can put in there.
6:51
Now one thing to always remember here
though is that this action is synchronous
6:54
meaning that it's in the request response
loop so users will be waiting for
6:58
this code here to execute.
7:02
So don't do anything too intense In here.
7:04
Awesome, right?
7:07
I know when I was first looking
at the spring data rest project
7:08
I was not very trusting.
7:11
I was like,
yeah sure I guess we do duplicate
7:13
a lot of code when we write APIs.
7:16
But where's all the business logic code?
7:17
Events are where you can inject that.
7:20
I've also found that these methods
make unit testing your business logic
7:22
simple and quick.
7:25
Speaking of testing,
it's outside the scope of this workshop.
7:27
But I do beg you to remember that
you don't need to test what has
7:30
already been tested by framework creator.
7:33
Remember your boundaries.
7:36
Test only what is your responsibility and
what could actually break.
7:37
I suggest you test your validation,
your security, and
7:41
that your custom events
are working as you intended.
7:43
But please don't go and
test status codes and
7:47
error message that you haven't customized.
7:49
Find the right balance, and
remember to not test what has been so
7:51
graciously abstracted away for you.
7:54
You need to sign up for Treehouse in order to download course files.
Sign up