Plan: What the Movie Catalog Service Needs to Do
What do we need to do? We need to go to the movie catalog service. The resource here, I'm doing a singleton list, but this will not do. What I want to do is get... actually there are a couple of steps here. Right, the first step is get all rated movie IDs and then for each movie ID call. The final step is to put them all together. Make sense? Now this is what I'm gonna be doing, right? The part where I'm calling the movie info service and getting the movie information back, that's what I'm gonna be doing. So I am going to hard-code the ratings for now.
Hard-Coding Ratings and Creating Model Classes
The way I do that is first I'm going to get the ratings resource. I'm going to copy this here, sorry the model. No, copy this here because we need the model. We need to store the ratings information. I paste it here and then here I'm going to hard-code just that part and create a list of rating. It's supposed to be done through a RestTemplate, so the communication happens through a RestTemplate. But then what you get back is going to be a string. You need objects to deal with the data. Whenever you in Java you need to deal with data, you need objects. The objects need to be of a particular class. So you couldn't create the class here, it happens to be the same exact class, so I've just copied that over. It'll return a string, but then you can also unmarshal it. Hold that thought for a bit. Okay, let's assume we are not doing RestTemplate; it's just hard coding the whole thing. The whole communication we hard coding, what would be the first step? You need to create a bunch of responses from the first API, how could a bunch of responses from the second API. Intended. So to hard code it you need classes. So that's what I'm doing here. So I'm creating an array of a bunch of ratings. Let's say 1, 2, 3, 4. Rating is 4, and then one more 5, 6, 7, 8. It's creating this three. Okay, let's assume this is the response we got from that rating data API, right? So somebody has come to us and said for this user give me all the movies he watched and details. So we have to first get the movie IDs he watched. That's what we hard-coding now. That we have the movies that they have watched, we need to get the details and for this you're gonna make the API call. How are you gonna make the API call? Using RestTemplate. So I'm going to loop through this, create a stream. I can either do a for loop or I can do a map. Let's say I do a map. So for each rating I need to replace rating with the catalog item.
Using RestTemplate.getForObject to Fetch Movie Info
All right, so I need to get that information here. Collectors toList. All right, make sense, and now I can return this. Questions about what I'm doing here? I've hard coded the ratings. For each rating I should be making a call to the API but I'm not doing that. I'm just creating a catalog element with hard-coded name and description. These name and description should actually come from the API, right? I'm hard coding it and then I'm making it a list and then returning that. Make sense? Now we're gonna change this to make a call for each of those movies. I'm gonna make a call to movie info, get the movie details, and that's what the user needs to see. All right, so I can do that. Over here I'm gonna make this a block. It's no longer a single line. What do I need to do? I need to first create an instance of RestTemplate. RestTemplate is going to be the utility object which lets me make these calls. Okay, so I'm going to say new RestTemplate. I'm gonna let me create this instance over here at the top. Create a new RestTemplate and the RestTemplate has methods on it, dot getForObject. Okay. What does this do? It takes in two arguments. The first argument is the URL that you want to call. This doesn't have to be a microservice. It could be any URL. It's gonna make a call, it's gonna make a REST call to it, right, and what it gets back is a string, right? It also helps you unmarshal it into an object. So if you know what the payload of that response is, in this case we know it's gonna be movie info, you can provide a class which has the same properties as the JSON and what this RestTemplate is going to do is it's going to create that instance of the class, populate those properties to it, and it's going to give you a fully-formed object, right. All that is happening in this one line. So it's two parameters. The first parameter is the URL. What's the URL? The URL is the movie URL here. It's localhost:8081 slash movies slash movieId. And then the second argument is the movie information. So this is a payload which has two properties: movieId and name. So I have a class sitting here which has just that so I'm just going to use it.
Model Copying in Microservices and Calling per Movie ID
See here this is a class which has the movieId and the name. You can technically create an entirely different class, it's perfectly fine, but I'm just gonna copy this. Now some of you might be asking, isn't it a bad thing to do copy paste of classes? You have duplicate copies of the same class all over the place. Isn't that something that's frowned upon? Well, in a monolithic application yes, you don't have multiple copies of the same class, but in the microservice this is technically allowed. Why? Because you can't—well you can avoid doing this, but let's say you want to create a library of all these model classes and then use that as a dependency in all these different things. What's the drawback of that? Somebody wants to change that, well you're gonna have to manage all those things and you defeat the purpose of microservices being independent things. Do you want to be able to deploy one without having to care about what the other team is doing? If you use the same shared library you're bound; the release cycles are bound, all that stuff. So it's perfectly okay to create copies of these classes. The side benefit of this is let's say there are more stuff there in that class that's beneficial for that microservice but you don't care about that, you can just use the fields that you want here. So those classes usually in my experience even though they start out as copies since they're completely different things they end up picking different parts and the class kind of diverged from there on and at that point people realize, oh it's a good thing we created those copies. So it's perfectly okay to create copies of these classes. You can, but then would it be sharing those interfaces? Because again you're gonna rent it— you can, you technically can, but then again you're gonna run in— yeah what if you need to change the interface and then you again have to dependency. So it's a little less likely that you're gonna change interfaces than the core classes, but then you never know. If it's not backward-compatible you will have to let people know. Versioning is a whole different topic when it comes to microservices. How do you version your microservices? If you are adding a new field it's fine; people who don't use it don't care and they can upgrade whenever they want. But if you're removing a field or what if you're changing the name of a field, then you have to let people know or maybe create a new version v1 API, right, to put it in a different URL so that you know if you want to get the new version you have to call the different URL. So it's a big topic in itself of how you manage versioning. All right, so back to RestTemplate. This is the line we were working on. Okay, this has to go somewhere else. It shouldn't be here. It should be this call for each rated movie. For every movie that the user has watched we need to fetch the data. But here this is the signature; this is what needs to happen whenever you need to make a call. This is what you need to do: RestTemplate.getForObject. You're saying get me the resource and unmarshal it into an object. It takes two arguments: one is the URL that it needs to get and the second is the class that it needs to unmarshal to. Just gonna take that payload and then it's going to return a Movie object. Right, as easy as that. So I'm gonna use this. I'm gonna use this piece, get rid of this here, and what I need to do here is for every rated movie I need to take that movieId and I need to call the movie information API with that ID. Okay, so I'm gonna call this but not with foo all the time. I'm going to append the rating.getMovieId. Okay, so for each iteration it's gonna make a separate call and what it gets back here is that particular movie. So first time it's gonna make a call to movieId one, two, three, four. Second it's gonna make a call to five, six, seven, eight. Yes, you can, and that's where the WebClient comes in and that's where it gets into the reactive program and you can make it asynchronous. But then when you make it asynchronous you have to make this asynchronous as well because if you are returning a single object you have to block until you get that object and return it. But there are ways in which you can return like a Mono or a Flux object from Spring controllers so that you're telling Spring, hey, I've set things in motion; whenever it returns, return it to the user and then you move on to do something else. So you can technically do that. If you guys are interested I'm happy to do, like, just not microservices, just a Spring Boot workshop where we just do asynchronous Spring Boot. So yeah, that's a whole different way of doing things. Okay, now that I have this Movie object which is just the movie we want, right, we've picked the ID, made a call just for the movie we want and now we can return the catalog item. But rather than hard code the name, I'm going to return movie.getName. Just making sense. I don't—I guess I don't have a movie description. Yeah, I don't have a description, so I'm just gonna hard-code the description for now and then the rating is going to be rating.getRating. Okay, so this is where I'm putting those two together. So this piece is the first API call, the movie info. This piece is the second API call to the rating database which we have hard-coded for now, but you know the idea is to convert it into a live API call later. Right, and then I do a collect to a list and return it back.
Fixes, Errors, Live Calls, and Final Takeaways
Restart this. I think I have a nimter—that's the semicolon. No, this one. There's an error. 404 seems very odd. Anybody ideas? Oh, okay, I see what you mean. Okay, yeah you're right, thank you. This is 8082. This is if you're doing a lot of bad things here I'm just gonna list out one what are the bad things we're doing, but we have to make this work first. Cannot construct an instance. Okay, so this is another thing that you have to watch out for when you have Java unmarshal something which is not an object to an object. You need to provide it an empty constructor. This Movie doesn't have an empty constructor, so I'm just gonna put that there. The way the marshaling and unmarshalling things work is Java first creates an instance and then parses the string and then populates one by one. So if you don't have an empty constructor it doesn't have anything to create an instance and that's why it's complaining. Yeah, yeah, so I have an overloaded constructor so that's the problem. And now if you see you get the values from the hard-coded ratings API call and the live data from the API. Of course it's not technically live data but it's making an API call. So what it's doing is actually making multiple API calls, right? So there you have a list of two items. For each item one microservice running on this separate Tomcat instance making a REST call to another microservice running on a separate Tomcat instance that returns back, it unmarshals it, and you're putting all the data together and returning it back. And look at the amount of code it took to do this. This is it; it's like three lines of code. So this is one of the reasons why Spring has become very popular. It does a lot of things for you behind the scenes, and other frameworks are kind of catching up as well.