Spring Boot - Why I cannot produce a String in RestController? - spring

In Spring Boot, I am configuring the server and everything is working, except of my RestController. I dont know why:
(SO doesnt allow to include pictures yet, so here is a link)
Thats the little Controller class. Notice, that the method name in my Intellij IDEA
is grey - it is not used.
package com.example.intermediate.controller;
import org.springframework.web.bind.annotation.*;
#RestController
public class GrakaController {
#GetMapping(value = "/graka", produces = "text/plain")
#ResponseBody
public String getSimpleString() {
return "IT WORKED!";
}
}
In Postman I try to get the String by using http://localhost:8080/graka: I am getting a 200 return code, but with empty response body, no matter which response body format I choose in Postman. But I should get "IT WORKED!" back I think.
I have been struggling for some hours with that. Who got any ideas? Thanks for every tip!

try this
#GetMapping("/graka")
public String getSimpleString(){
return "IT WORKED!";
}

With Spring 4, if your Controller is annotated with #RestController, you don't need the #ResponseBody annotation.
Use ResponseEntity.
#GetMapping("/graka")
public ResponseEntity<String> getSimpleString() {
LOG.info("REST request get string value");
return new ResponseEntity<>("{\"status\" : \"IT WORKED!\"}", HttpStatus.OK);
}

Related

Wrapped Response by ResponseBodyAdvice in Spring Boot not showing up in Swagger. Any idea how could it be done?

#ControllerAdvice
public class CA implements ResponseBodyAdvice<Object> { }
This class will wrap the response
#GetMapping
public Person getPerson()
{
return new Person();
}
In Swagger I want it to show WrappedResponse but instead it shows response of return type here(Person).
What changes to make so that it will show the wrapped response ?
Tried different combinations of APIReponse, APIModel, APIResponses of swagger but nothing seems to work

How to write appropriate endpoint in Spring Boot for GET request?

I have an assignment to write simple GET request.
The format that is going to be typed in URL is like this:
http://localhost:8080/api/tasks/20-08-2020
Server should return TODOs for that date. I did managed to write a finder method. But not sure how to write an endpoint. This is what I have so far:
#GetMapping(value = "/{date}", consumes="application/json")
public ResponseEntity<List<Task>> getTasksByDateUsingURL(#PathVariable("date") #DateTimeFormat(pattern="dd-MM-yyyy") #Valid LocalDate dueDate){
List<Task> tasks = taskService.getAllTasksByDate(dueDate);
return new ResponseEntity<List<Task>>(tasks,HttpStatus.OK);
}
This is inside RestController class:
#RestController
#RequestMapping(value="/api/tasks")
public class TaskController {...}
I cannot hit this GET endpoint...
Workaround for your problem is to get the string as parameter and parse it manually
#GetMapping(value = "/{date}", consumes="application/json")
public ResponseEntity<List<Task>> getTasksByDateUsingURL(
#PathVariable("date")
String date
){
LocalDate dueDate = parse(date);
List<Task> tasks = taskService.getAllTasksByDate(dueDate);
return new ResponseEntity<List<Task>>(tasks,HttpStatus.OK);
}
private LocalDate parse(String stringDate) {
// TODO
}
As author said in comments:
When try to call the endpoint from browser, the mapping is not executed.
Seems like that the browser is sending request with wrong Content-Type header. Your mapping is explicitly requires only application/json value.
When try to call the endpoint from Postman, the application returns 400 status.
I could not see the body of response, but I guess the problem is #Valid annotation on the parameter. How should Spring validate the LocalDate?
So the solution is to remove consumes="application/json" from mapping or send corresponding Content-Type value
and remove #Valid annotation from parameter.

My spring controller test doesn't enter controller

I am trying to test spring controller using mockMvc. There is existing functionality, so I referenced it as I was creating my test since I am new to spring controller. While existing test works fine, my test doesn't go into the spring controller I expected to. Here is my test:
#Test
public void updatePriorityStudyDispatch() throws Exception {
DispatchStudyPriorityRequest request = TestDataFactory.getDispatchStudyPriorityRequest();
mockMvc.perform(post(BASE_URL, getDispatchId(WORKSTATION_ID_VALUE, STUDY_ID_VALUE))
.accept(PowerShareMediaType.PSH_GATEWAY_STUDYDISPATCHER_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(gson.toJson(request)))
.andExpect(status().isOk());
verify(studyDispatcherService)
.updatePriority(WORKSTAION_ID, STUDY_ID, TestDataFactory.getDispatchStudyPriorityRequest());
}
and here is my controller:
#PostMapping(path = "/{dispatchid}", produces = PowerShareMediaType.PSH_GATEWAY_STUDYDISPATCHER_JSON)
public ResponseEntity<Void> updatePriority(#PathVariable("dispatchid") String dispatchId,
#Valid #RequestBody DispatchStudyPriorityRequest request) {
...
...
...
}
I had a break points on my controller and it seems like it never enters it when I run the test. My result is 400 when I am expecting 200. I am not sure what is happening.
The one that is working basically have different "request" object (different model). Same BASE_URL, same ID_VALUEs, same MediaTypes. Here is controller
#PutMapping(path = "/{dispatchid}", produces = PowerShareMediaType.PSH_GATEWAY_STUDYDISPATCHER_JSON)
public ResponseEntity<Void> dispatchStudy(#PathVariable("dispatchid") String dispatchId,
#Valid #RequestBody StudyDispatchRequest request) {
I think it has something to do with RequestBody, but this is first time I am using RequestBody with some object. I learned that there is spring functionality that converts incoming Json file to object. However, I am really new to this concept, so it is hard for me to understand the issue.
I found why it was happening. It was giving me 400 because Date() field in the DispatchStudyPriorityRequest object was in Gson format. Somehow Json format wasn't able to parse it correctly.
Gson format was something like "Jun 12, 2020" while Json format should have been "yyyy-mm-dd".

Problems implementing an easy REST service - Spring MVC

I have a Springboot application (a videoclub application). I do not think it is necessary to show you all the code as it would be very verbose. But it works fine.
A class Film, and FilmRepository with some methods, a controller, database JPA, and the HTML files. Everything works fine. I am not looking for a code solution, but more for a "conceptual" solution, just to know if I am implementing properly the REST service.
I want to add now a really easy REST service (adding a class "MyRestController") that will search for a film just by adding the name of it in the URL.
So apart from my Controller, I want to add this RestController just to do this simple thing: If I add the name of a film in the URL, it will search for it with the normal MVC methods.
But adding what I think is the solution gives me this error:
There was an unexpected error (type=Not Found, status=404).
No message available
So when going through the HTML content to the page to search for the film, and adding to that /buscar the film name (which I have in the db) /buscar/Interstellar, it shows the before error.
#CrossOrigin
#RestController
public class MyRestController {
#Autowired
private FilmRepository filmRepo;
#RequestMapping(value = "/buscar", method = RequestMethod.GET)
public ResponseEntity<List<Film>> getFilms(#RequestParam String Title) {
List<Film> pelis = (List<Film>) filmRepo.findByTitle(Title);
HttpStatus status = HttpStatus.OK;
ResponseEntity<List<Film>> response = new ResponseEntity<>(pelis, status);
return response;
}
}
Getting this error makes me think the page knows it has to do something, but might be having trouble getting it (due to strings, iterable things, lists, or that sort of problem, JSON maybe). But I do not know if the "theory" behind the rest service is alright in MyRestController.
Film repository:
public interface FilmRepository extends CrudRepository<Film, Long>{
Iterable<Film> findByTitle(String Title);
}
(The MVC method in the normal controller)
#RequestMapping("/buscar")
public ModelAndView processSearch(#RequestParam(value = "title", required = false) String title) {
if (title == null || title == "") {
Iterable<Film> films = filmRepo.findAll();
return new ModelAndView("buscar").addObject("films", films);
}
Iterable<Film> films = filmRepo.findByTitle(title);
return new ModelAndView("buscar").addObject("films", films);
}
What you're talking about is a #PathVariable
#RequestMapping(path={"/buscar","/buscar/{title}"})
public ModelAndView processSearch(#PathVariable(value = "title", required=false) String title) {
In the end, the problem was with the #RequestParam, which makes you search in the URL with a query like: /buscar?Title=Interstellar
#RequestMapping(value = "/buscar/{title}", method = RequestMethod.GET)
public ResponseEntity<List<Film>> getFilms(#PathVariable String title) {
List<Film> pelis = (List<Film>) filmRepo.findByTitle(title);
HttpStatus status = HttpStatus.OK;
ResponseEntity<List<Film>> response = new ResponseEntity<>(pelis, status);
return response;
}
With this REST service, you can search by URL like "/buscar/Interstellar".
The result is going to give you JSON content with all the information of the Object Film.

Conditionally returning both JSON and (HTML) templates from #RestController in Spring Boot

Most of the similar questions seem to have the opposite problem I’m having.
I’m building a Spring Boot-based webapp using #RestController. The JSON responses work well, but now I want to support returning HTML via templates (Thymeleaf, specifically). All the examples show building methods like this:
#RequestMapping(method = RequestMethod.GET)
String index()
{
return "index";
}
And that works fine, so long as the class it’s in is annotated with #Controller. If I annotate with #RestController, I get the literal string "index" back. This makes sense, since #RestController implies #ResponseBody.
I have a few questions about this in general…
Is the right thing to do to use #Controller and explicit #ResponseBody annotations on the methods designed to return JSON?
I worry that my Controller classes will grow quite large, as I’ll have two implementations for most of the GET methods (one to return the HATEOAS JSON, one to return HTML with a lot more stuff in the model). Are there recommended practices for factoring this?
Advice is appreciated. Thanks!
Is the right thing to do to use #Controller and explicit #ResponseBody annotations on the methods designed to return JSON?
It is as long as your controllers are small and contain only few methods.
I worry that my Controller classes will grow quite large, as I’ll have two implementations for most of the GET methods (one to return the HATEOAS JSON, one to return HTML with a lot more stuff in the model). Are there recommended practices for factoring this?
If they grow and become hard to read split into one #Controller returning HTML pages and #RestController returning JSON.
To summarise, focus on readability. Technically both approaches are correct.
#RestController
public class SampleController {
#GetMapping(value = "/data/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public CustomClass get(#PathVariable String id) {
return newsService.getById(id);
}
#GetMapping(value = "/data/{id}", produces = MediaType.TEXT_HTML_VALUE)
public String getHTML(#PathVariable String id) {
return "HTML";
}
}
Instead of a String you can return a View or a ModelAndView:
#RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
ModelAndView index()
{
return new ModelAndView("index");
}
That allows you to return HTML from controllers annotated with #RestController.

Resources