Multiple Get Requests with Spring Boot, WebClient and Thymeleaf - java

I'm trying to make a RESTClient application for consuming the Starwars API.
I take the following URL: https://swapi.py4e.com/api/films/
The user logs in my website and can search for a film (introducing the id in a form).
Later, the website shows title, director, release date and a the list of characters.
For instance, if the user inserts 1 (https://swapi.py4e.com/api/films/1), he should get the following info on screen:
{
"title": "A New Hope",
"episode_id": 4,
"director": "George Lucas",
"characters": [
"https://swapi.py4e.com/api/people/1/",
"https://swapi.py4e.com/api/people/2/",
"https://swapi.py4e.com/api/people/3/",
"https://swapi.py4e.com/api/people/4/",
"https://swapi.py4e.com/api/people/5/",
"https://swapi.py4e.com/api/people/6/",
"https://swapi.py4e.com/api/people/7/",
"https://swapi.py4e.com/api/people/8/",
"https://swapi.py4e.com/api/people/9/",
"https://swapi.py4e.com/api/people/10/",
"https://swapi.py4e.com/api/people/12/",
"https://swapi.py4e.com/api/people/13/",
"https://swapi.py4e.com/api/people/14/",
"https://swapi.py4e.com/api/people/15/",
"https://swapi.py4e.com/api/people/16/",
"https://swapi.py4e.com/api/people/18/",
"https://swapi.py4e.com/api/people/19/",
"https://swapi.py4e.com/api/people/81/"
],
The urls from the characters should show the name of the characters.
This should make, I think, an in-between get request to (for example) the urls and stock them in a list, set or array.
For instance: https://swapi.py4e.com/api/people/1/, I only need the name.
{
"name": "Luke Skywalker",
}
For that, I have the following code snippets (I'm using Spring Boot, MVC and working with layers, as in an enterprise application):
DefaultSWAPIClient (with an interface SWAPIClient):
#Component
class DefaultSWAPIClient implements SWAPIClient {
private final WebClient client;
private final String filmURI;
DefaultSWAPIClient(
WebClient.Builder builder,
#Value("${swapi.films}") String filmURI) {
client = builder.build();
this.filmURI = filmURI;
}
#Override
public Optional<Film> findByEpisodeId(long id) {
try {
return Optional.of(
client.get()
.uri(filmURI, uriBuilder -> uriBuilder.build(id))
.retrieve().bodyToMono(Film.class).block());
} catch (WebClientResponseException.NotFound ex) {
return Optional.empty();
}
}
}
DTO (of DAO) film class:
public class Film {
#JsonProperty("title")
private String title;
#JsonProperty("episode_id")
private long episodeId;
#JsonProperty("director")
private String regisseur;
#JsonProperty("release_date")
private String releaseDate;
#JsonProperty("characters")
private LinkedHashSet<String> characters = new LinkedHashSet<String>();
public String getTitle() {
return title;
}
public long getEpisodeId() {
return episodeId;
}
public String getRegisseur() {
return regisseur;
}
public String getReleaseDate() {
return releaseDate;
}
public LinkedHashSet<String> getCharacters() {
return characters;
}
}
The search film Controller (FilmZoekenController):
#Controller
#RequestMapping("filmzoeken")
class FilmZoekenController {
private final SWAPIClient client;
FilmZoekenController(SWAPIClient client) {
this.client = client;
}
#GetMapping
public ModelAndView toonForm() {
return new ModelAndView("filmzoeken");
}
#GetMapping("/film/{id}")
public ModelAndView getData(#PathVariable long id) {
var modelAndView = new ModelAndView("film");
client.findByEpisodeId(id)
.ifPresent(film -> modelAndView.addObject(film));
return modelAndView;
}
}
Then I show all of it in a thymeleaf template.
I don't understand how to make another GET request to the api before it returns the data.
To sum up: I want to do a get request to films/{id} through a form, get some attributes (one being an array of urls, which need to returns the name value from each direction, so I assume another get request within) and show them to the user.
I hope that this should be enough info/code to help me out! Thanks in advance.

Related

I want to send a List(which is a member of an object) from Postman to Spring REST API

I have an object, and of its attributes is a List. I want to send this object from Postman to my service. I'm using Spring 5.2.7 (Spring MVC, not SpringBoot) and Hibernate 5.4.17 and Java 8. My problem is very similar to this one: I want to send a Postman POST request with an Array: members: ["william", "eric", "ryan"]
This is the class I'm trying to pass in Postman (POST method):
public class ChatDescriptionDto {
private String chatID;
private List<String> members;
private String chatType;
public String getChatID() {
return chatID;
}
public void setChatID(String chatID) {
this.chatID = chatID;
}
public List<String> getMembers() {
return members;
}
public void setMembers(List<String> members) {
this.members = members;
}
public void addMembers(List<String> members)
{
if(this.members == null)
this.members = new ArrayList<>();
this.members.addAll(members);
}
public void addMember(String member)
{
if(this.members == null)
this.members = new ArrayList<>();
this.members.add(member);
}
public String getChatType() {
return chatType;
}
public void setChatType(String chatType) {
this.chatType = chatType;
}
}
I've tried this and it didn't work:
{
"chatID": "123",
"members": ["P2001222833","P2001640916"],
"chatType": "personal"
}
Edit: This is my controller:
#PostMapping("/initiateChat")
public String initiateChat(#RequestBody ChatDescriptionDto chat)
{
return chatServiceLocal.initiateChat(chat)?"Chat Description created":"Failure! Could not save.";
}
Edit 2: The method which I've written in the question, "members": ["P2001222833","P2001640916"], is the correct one. Turns out, there was some error in the server so it never started and I didn't check that.
Having no information about the Controller class you're using, the first thing I'd assume is that you're receiving an empty object, which means that Spring simply skipped the serialization. This is the case when you don't specify the parameter of the method as #RequestBody. First, make sure that you do have the annotation.
#RestController
#RequestMapping("/")
public class TestController {
#RequestMapping(value = "/test", method = RequestMethod.POST)
public ResponseEntity test(#RequestBody ChatDescriptionDto dto) {
System.out.println(dto);
return ResponseEntity.ok().build();
}
}
If that's not the case, I'd assume that the problem is with the content type you're using. Spring uses JSON by default, but you can change it in your endpoint's configuration.
To send a simple object request, you do:
{
"member":"kola"
}
To send a list object request, you do:
{
"member": ["kola","wale","ojo"]
}
This is more like listing array elements.
Any error that pops up after this, is basically not because of the request you sent.

How do I pass list of objects to Rest API POST Method?

I'm creating a Spring boot REST API which should take 2 Lists of custom objects. I'm not able to correctly pass a POST body to the API I've created. Any idea what might be going wrong ?
Below is my code :
Controller Class Method :
// Main controller Class which is called from the REST API. Just the POST method for now.
#RequestMapping(value = "/question1/solution/", method = RequestMethod.POST)
public List<Plan> returnSolution(#RequestBody List<Plan> inputPlans, #RequestBody List<Feature> inputFeatures) {
logger.info("Plans received from user are : " + inputPlans.toString());
return planService.findBestPlan(inputPlans, inputFeatures);
}
Plan Class , this will contain the Feature class objects in an array:
public class Plan {
public Plan(String planName, double planCost, Feature[] features) {
this.planName = planName;
this.planCost = planCost;
this.features = features;
}
public Plan() {
}
private String planName;
private double planCost;
Feature[] features;
public String getPlanName() {
return planName;
}
// getters & setters
}
Feature POJO Class :
// Feature will contain features like - email , archive etc.
public class Feature implements Comparable<Feature> {
public Feature(String featureName) {
this.featureName = featureName;
}
public Feature() {
}
private String featureName;
// Getters / Setters
#Override
public int compareTo(Feature inputFeature) {
return this.featureName.compareTo(inputFeature.getFeatureName());
}
}
You cannot use #RequestBody twice!
You should create a class that holds the two lists and use that class with #RequestBody
You should create json like this:
{
"inputPlans":[],
"inputFeatures":[]
}
and create Class like this:
public class SolutionRequestBody {
private List<Plan> inputPlans;
private List<Feature> inputFeatures;
//setters and getters
}
POST mapping like this:
#RequestMapping(value = "/question1/solution/", method = RequestMethod.POST)
public List<Plan> returnSolution(#RequestBody SolutionRequestBody solution) {
logger.info("Plans received from user are : " + solution.getInputPlans().toString());
return planService.findBestPlan(solution);
}

Spring boot restful web service. Xml response wrongly formatted

I've got a simple Restful webService using Spring Boot 2.1, Java 8, running on Eclipse Neon. Im sending the following request:
<patentListWrapper>
<patentList>
<patent>
<guid>bbb</guid>
</patent>
<patent>
<guid>ccc</guid>
</patent>
</patentList>
</patentListWrapper>
and im getting back the following (incorrect) response:
<patentListWrapper>
<patentList>
<patentList>
<guid>ddd</guid>
</patentList>
<patentList>
<guid>eee</guid>
</patentList>
</patentList>
</patentListWrapper>
ie i've got 2 patentList elements in the response ,instead of an inner patent element, and I don't know why. My 2 POJO classes to map the request are:
public class PatentListWrapper {
private List<Patent> patents;
public List<Patent> getPatentList() {
return patents;
}
public void setPatentList(List<Patent> patents) {
this.patents = patents;
}
}
and:
public class Patent {
private String guid;
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public Patent() {
super();
}
}
my REST Controller class is:
#RestController
public class PndController {
#Autowired
ReadFromDb db;
#RequestMapping(value = "/guidRequest/xmlList", method = RequestMethod.POST, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )
public PatentListWrapper guidSearchList(#RequestBody PatentListWrapper patentListWrapper) {
System.out.println("DS in guidSearchList()");
patentListWrapper = db.readGuidsFromDb(patentListWrapper); // Set the guid in the patents List in patentListWrapper
return patentListWrapper;
}
}
and ReadFromDb class:
#Repository
public class ReadFromDb {
public PatentListWrapper readGuidsFromDb(PatentListWrapper patentListWrapper) {
List<Patent> patents= patentListWrapper.getPatentList();
for(Patent patent : patents) {
patent.setGuid("aaa");
}
patentListWrapper.setPatentList(patents);
return patentListWrapper;
}
}
I'm sending my resuest using the windows ARC Advanced Rest Client:
Rest client with Content-type=application/xml
I've established that both patentList element names map to getPatentList() in PatentListWrapper. How do I get the response envelope to match the request envelop? Any help appreciated.
it is true , just create the getter setter method with the same variable name like below instead of using different names for getter setter methods
private List<Patent> patents;
public List<Patent> getPatents() {
return patents;
}
public void setPatents(List<Patent> patents) {
this.patents = patents;
}
or use the GSON and use #JsonProperty and define the required value name , further if you are not using the IDE to generate getters and setters you better use lombok plugin .

Return a status to Angular when creating object

In my app users can add movie titles to their watchlist. In my component I have this function:
createMovie(movie: Movie): void {
this._dataService.createMovie<Movie>({'name': 'Star Wars', 'id': 111, 'description': 'A war in the Stars'})
.subscribe((data) => this.movies.push(data),
error => () => {
'something went wrong';
},
() => {
// console.log(this.movies);
});
}
This has some dummy info for now.
In my service I have:
public createMovie<T>(movie: Movie): Observable<T> {
return this.http.post<T>('/api/movies/', movie, {headers: this.getToken()});
}
So I pass the movie object and the token to the back-end.
In my MovieController.java I have:
#RestController
#RequestMapping("api/movies")
public class MovieController {
#Autowired
private MovieService movieService;
#RequestMapping(value = "/", method = RequestMethod.POST)
public Movie createMovie(#RequestBody Movie movie){
return movieService.createMovie(movie);
}
}
And the createMovie function in the movieService:
#Override
public Movie createMovie(Movie movie) {
movieRepository.save(movie);
User current_user = userService.getUser();
current_user.addMovie(movie);
userRepository.save(current_user);
return movie;
}
This all works fine, but I would like to return a message to the angular application when a movie was successfully added to the list (database). I think I should use #ResponseBody for it, but I'm unsure how to return the movie object and a status text to the angular application.
So for example, when a movie is added I would like to return a message "movie.name was successfully added to your watchlist" from the back-end.
To return a message alongside your object you can define a new class like
public class RestResponse<T>{
private String message;
private T obj;
public RestResponse(String message, T obj){
this.message = message;
this.obj = obj;
}
}
then in your Rest controller you can do
Movie result = movieService.createMovie(movie);
return new RestResponse<Movie>(String.format("%s was added to your watchlist", movie.name ), result);

Java spring REST controller: incomplete request body

I have a problem with my REST Controller. If I sent a request with a RequestBody (json) some attributes doesn't arrive the controller, although they was sent and defined at model.
I could find out that it look like an old version of files will be used from the local java web server. As I changed the System.out.println Value at Constructor still the old value was outputed.
public RestController_ApiKey_2_0() {
System.out.println("RestController_ApiKey_2_0 init");
}
I tried the following things bootless:
deleted java web server and did a new installation
cleaned the project and started server again
clean install of project
Does anyone have an idea?
Please provide more code, how do you declare a controller, and what params it can take. Also show a sample request.
Here is an example of a simple controller:
A model
public class CustomRequestBody {
private String fieldA;
private String fieldB;
public String getFieldA() {
return fieldA;
}
public void setFieldA(final String fieldA) {
this.fieldA = fieldA;
}
public String getFieldB() {
return fieldB;
}
public void setFieldB(final String fieldB) {
this.fieldB = fieldB;
}
}
Controller:
#Controller
public class MyController {
#RequestMapping(value = "/some-path", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.ACCEPTED)
public ResponseEntity handleSomePath(#RequestBody final CustomRequestBody body, final HttpServletRequest request) {
// Do the job.
}
And request will be:
HTTP POST http://some.server.com/some-path
{
"fieldA":"first value",
"fieldB":"second value"
}
Read more at Spring documentation here

Categories

Resources