Is Springdoc swagger not possible when passing HttpServletRequest as method param? - spring-boot

I have below springboot rest controller and using springdoc-openapi. My springboot rest service has to cater to some legacy application( which is the only client which calls this service) and I need to have HttpServletRequest as param.
I am generating swagger openapi doc and when I got to swagger-ui.html, I see that the rerquest body comes for Httprequest param method with uri path = '/personhttprequest' but not when param is HttpServletRequest. I see here
https://springdoc.org/faq.html#what-are-the-ignored-types-in-the-documentation
But I am not clear why and how can I get HttpServletRequest param working in swagger ui. I want to pass it as text/xml just like i can make it work for HttpRequest below.I have attached scrrenshot for "/personhttprequest" and you see the box for request body as xml comes up. How can make it work for "/personhttpservletrequest"?
#RestController
public class PersonController {
#RequestMapping(path = "/personhttprequest", method = RequestMethod.POST,consumes=MediaType.TEXT_XML_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
public Person personHttpRequest(HttpRequest req) {
Person person = new Person();
return person;
}
#RequestMapping(path = "/personhttpservletrequest", method = RequestMethod.POST,consumes=MediaType.TEXT_XML_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
public Person personHttpServletRequest(HttpServletRequest req) {
Person person = new Person();
return person;
}
}
Here is git hub :
https://github.com/vmisra2018/sb-example-swaggerdoc

Principal, Locale, HttpServletRequest and HttpServletResponse and other injectable parameters supported by Spring MVC are excluded.
Full documentation here:
https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/web.html#mvc-ann-arguments.
If you don't want to ignore it:
SpringDocUtils.getConfig().removeRequestWrapperToIgnore(HttpServletRequest.class)

Related

Error 400 when receiving data from URL parameters en Spring MVC

I am trying to receive data from an URL with two parameters like this one:
http://localhost:80000/xxx/xxx/tickets/search?codprovincia=28&municipio=110000
No matter the approach, I am always getting a 400 error, but if I access the URL without the two parameters, the controller returns the view correctly (without the parameters, naturally)
This is the code of my controller:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping("tickets")
public String tickets(Model model, #RequestParam ("codprovincia") String codprovincia, #RequestParam ("municipio") String municipio, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
Extra info: if I use this URL:
http://localhost:9081/xxx/xxx/tickets/search/28/790000
And this code:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping(value = "buscar/{codprovincia}/{municipio}", method = RequestMethod.GET)
public String buscar(#PathVariable Integer codprovincia, #PathVariable Integer municipio ,Model model, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
It gets the parameters correctly. The problem is that I have to use the first URL. I have reviewed similar questions about similar issues, and I have implemented the solutions to those issues, but I get the 400 error regardless what I try (add value="xxx=, required=false, and other suggestions.)
For RequestParam, you need to explicitly add 'name' attribute
#RequestParam(name = "codprovincia"), #RequestParam (name = "municipio")
No need to for HttpServletRequest, unless you have reason
Also, in your 'tickets' method, RequestMapping is not conforming to your URL path.
I think it should be
#RequestMapping("/xxx/tickets/search")
Cheers!

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.

How to Forwarding Requests from a Controller to Another Controller Programmatically in Spring MVC

Nowadays, I've been making an API system and I've got stuck in a problem regarding forwarding requests.
In my API system, all of requests from users come to proxy controllers first, and then the requests are forwarded to real API versionized.
// proxy controller
#Controller
#RequestMapping("/proxy")
public class ProxyController {
private static final String VERSION = "v1";
#RequestMapping(value = "/users", method = RequestMethod.GET)
public String getUsers() {
return String.format("forward:/%s/users", VERSION);
}
}
// Real API controller
#RestController("v1UsersController")
#RequestMapping("/v1/users")
public class UsersController {
#RequestMapping(value = "/users", method = RequestMethod.GET)
public ApiResultsResponse<Users> findUsers(#RequestParam userId, ...) {
// ...
// ...
// ...
// return users found
}
I've located the proxy controller because I could easily change the real api when some case happens like upgrading version of the api.
However, because I've used forwarding with String(in this case, return String.format("forward:/%s/users", VERSION)), I'm not sure whether the forwarded real api exist or not currently.
So I'd like to be sure this by calling the real api's controller method directly. If so, when the called method doesn't exists, I can notice this with compile errors. The problem is, I gotta synchronize parameters condition of real api handler with proxy's.(It's kinda dirty works.)
Is it possible to call forwarded controller method directly with using the same HttpServletRequest object?
You could use spring HandlerInterceptorAdapter to intercept before call your controllers
Maybe this solution will help you.
#RequestMapping(value = "/users", method = RequestMethod.GET)
public void getUsers(HttpServletRequest request,HttpServletResponse response) {
String path = String.format("forward:/%s/users", VERSION);
RequestDispatcher dispatcher=request.getRequestDispatcher(path);
dispatcher.forward(request, response);
}

How is a custom derived query POST added to spring data REST?

I have a Spring data REST project I am using to learn.
Right now I want to set up a query in this repository:
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long>
namely, this guy:
#RestResource(path = "login", rel = "login")
User findByUsernameAndPassword(String username, String password);
A basic repository is easy to set up. So are custom GET requests like:
List<Item> findByType(#Param("type") String type);
or
#RestResource(path = "byMaxPrice")
#Query("SELECT i FROM Item i WHERE i.price <= :maxPrice")
List<Item> findItemsLessThan(#Param("maxPrice") double maxPrice);
But these are still GET requests. I would like to use a POST request. The method = RequestMapping.POST markup isn't accepted by #RestResource .. and I dont see any mention of different request types in the documentation. how do I do this?
You need to define a custom Controller to handle POST requests. If you just want to do POST for the default Repository methods, unfortunately, you still have to make a pass through Controller
#RepositoryRestController
public class MyController implements Serializable {
...
#RequestMapping(value = "/myConstroller/myPostMethod", method = RequestMethod.POST
, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody List<MyObjects> updateMyObjectList(
#RequestBody List<MyObjects> objects) {
// Call your repository method here, or a custom service, or whatever
}
See Spring MVC docs for further information, specifically section 5.2.1, which describes the default HTTP Method support for Repositories, and 16.4, which gives a custom Controller example.
From 5.2.1:
POST
Creates a new entity from the given request body.
Thus, POST is supported, but not to do what you are trying to do. If you want to "hide" URL parameters by using POST instead of GET, you need a custom Controller.

Spring MVC to Spring REST tutorials misunderstanding

I have developed a Spring MVC - Hibernate application as told here.
Now I am trying to modify this code to create a REST application as told here.
I have added Jackson library to the classpath and added #XmlRootElement.
#XmlRootElement(name = "persons")
public class Person implements Serializable {
But if I do a application/json request then I still get the html code back.
What I am doing wrong / forgot to do?
My controller:
#RequestMapping(value = "/persons", method = RequestMethod.GET)
#ResponseBody
public String getPersons(Model model) {
logger.info("Received request to show all persons");
// Retrieve all persons by delegating the call to PersonService
List<Person> persons = personService.getAll();
model.addAttribute("persons", persons);
return "personspage";
}
Changed the Controller, but get an error:
t
ype Status report
message /Buddies/WEB-INF/jsp/main/persons/1.jsp
description The requested resource (/Buddies/WEB-INF/jsp/main/persons/1.jsp) is not available.
Your controller should look like this:
#RequestMapping(value = "/persons/{id}", method = RequestMethod.GET)
#ResponseBody
public Person getPerson(#PathVariable int id) {
Person person = personService.getPersonById(id);
return person;
}
If you want to return a list of Person objects, you need an extra wrapper object, see: Using JAXB to unmarshal/marshal a List<String>.
You are probably missing AnnotationMethodHandlerAdapter and messageConverter in your spring configuration.

Resources