Spring REST - Deserializing object from GET request query - spring

I'm trying to implement an endpoint that takes a serialized object from request parameter and deserializes it into a POJO. Is there an easy way how to do this with Spring?
The example of a query:
http://localhost/routes/departures?trip=%7B%22stopId%22:%22U321Z102%22,%22routeId%22:%22L991D1%22,%22headSign%22:%22Nemocnice+Motol%22%7D
which should translate into this:
trip: {"stopId":"U321Z102","routeId":"L991D1","headSign":"Nemocnice Motol"}
Also, those parameter values may contain spaces and special characters (ěščř...). Will Spring handle this? Alternatively I could send those parameters separately and not serialized, but I'm worried this would be an issue.

You need to send the user by using post request (send a userDTO that has the same type and attributes names than the one in the back end )
your rest controller is going to look like this
#PostMapping("/users")
#PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<User> createUser(#Valid #RequestBody UserDTO userDTO) throws URISyntaxException {
log.debug("REST request to save User : {}", userDTO);

Related

How to display x-www-form-urlencoded format request with springdoc-openapi-ui

My environment
springboot:2.6.4
springdoc-openapi-ui:1.6.6
Probrem
I want to create an API definition to receive requests in x-www-form-urlencoded format.
Using #RequestBody will create a swagger-ui display with no Parameter notation, just the body. However, when receiving a request in x-www-form-urlencoded format, it is necessary to receive it with #RequestParam, and if this is done, the swagger-ui display is created as a query parameter.
#PostMapping(value = "/v1/hoge")
public ResponseEntity<SampleResponse> postProc(
#RequestParam("param1") int param1,
#RequestParam("param2") String param2,
#RequestParam("param3") String param3,
HttpServletRequest request) {
  ・・・
}
swagger-image
However, since there is no actual query parameter, I do not want to display the Parameter in the same way as when receiving a request with #RequestBody.
The display without parameters is correct, as in POST /user in the following link.
http://158.101.191.70:8081/swagger-ui/4.5.0/index.html#/user/createUser
Is there a solution to this problem?
I might have a solution for you:
#PostMapping(value = "/v1/hoge", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<SampleResponse> postProc(
#RequestPart("param1") int param1,
#RequestPart("param2") String param2,
#RequestPart("param3") String param3,
HttpServletRequest request) {
  ・・・
}
In a perfect world, you could stick to the #RequestParam but I believe there is currently a bug with springdoc that make it impossible.

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.

Get request body as string/json to validate with a json schema- Spring boot REST API

I'm trying to validate JSON (passed by a client as a request body) before it is converted into a model in Controller method.
If validation passes then return nothing, let the process continue as it was (spring boot to convert JSON into a model marked as #RequestBody). Throw error in case validation fails (everit-org/json-schema).
I tried to two way:
Implement HandlerMethodArgumentResolver, but resolveArgument() doesn't give request body details as it is already read and stored in ContentCachingRequestWrapper.
NOTE: inputStream in ContentCachingRequestWrapper doesn't have any request body details.
Using spring Interceptor. But this doesn't help me to find request body type passed in the request. As JSON schema is different for each request.
Any other approaches I can try with?
I cannot add a comment ... so ...
What kind of validation do you need? If you only want to validate the fields like length of a string or range of a number and so on. I recommend you use #Validated on controller mehtod parameter, and model:
#NotNull
#Size(min = 32, max = 32)
private String id;
controller:
#PatchMapping
public Object update(#RequestBody #Validated User user, Errors errors) {
...
}
If there is something wrong, errors.hasErrors() will return true.
edit:
OK, I did some tests, in a filter :
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
ServletInputStream inputStream = httpServletRequest.getInputStream();
byte[] a = new byte[1024];
inputStream.read(a);
System.out.println(IOUtils.toString(a));
I got a json string (a piece of request body) :
{"template":"5AF78355A4F0D58E03CE9F55AFA850F8","bd":"" ...

Read query string parameters in Spring REST API (POST)

My Spring REST API is decorated as follows:
In below, I am confused weather, parameters such as list, operation need to be part of Url as query string or do they need to be part of Request Body as form data (Url encoded).
There are situations where I am sending these parameters in query string and it works fine. But couple of my api's are not working properly on production and they work only if I send the data in request body as Url encoded. Can anyone help me explain this behaviour ?
#RequestMapping(value = "/bulkupdate/{companyId}", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> bulkupdateArticle(#RequestParam("list") String documentIdList,
#PathVariable("companyId") String companyId, #RequestParam("operation") String operation){
try{
Looking at the resource I find that it could be better designed in a more REST-ful fashion. I don't like to see POSTed data in the reside in the url.
Next to becoming more Rest-ful it would also make live for you much easier.
I would create a Data Transfer Object and pass it as the body of the POST request to your resource/spring controller.
Going from your data:
public class ArticleToUpdate {
private String list; // list of what ? Maybe design it like List<String> somethingMoreMeaningFull
private String operation;
// .. getters
}
public ResponseEntity<String> bulkupdateArticle(#RequestBody ArticleToUpdate articleToUpdate) {
// .. do whatever you need with the posted data
Now you can post a JSON or XML document in the body which will probably life much easier.
Additionally you could also add validation on the posted data through #Valid support now.

In Spring MVC 3 how can you consume the following x-form-urlencoded request body?

Request body is like the following:
invoice[id]=111&invoice[billingDatetime]=2012-02-03T21:49:33+00:00&customer[code]=MILTON_WADDAMS&transaction[id]=f5574752-4eb0-11e1-a628-40403c39f8d9&transaction[transactedDatetime]=2012-02-03T21:49:33+00:00&invoice[type]=subscription&transaction[amount]=651.85&transaction[response]=approved&invoice[invoiceNumber]=3524&customer[id]=kui
I have the following code to handle the above request but it can not parse request body into the invoice and customer objects. Any suggestion is greatly appreciated!
public ModelAndView postPaymentSuccess(#ModelAttribute("invoice") Invoice invoice,#ModelAttribute("customer) Customer customer,HttpServletRequest req, HttpServletResponse res) {
.......}
If you want your form to represent multiple objects, it's often simpler to create a new object to represent the whole form, and have that new object have fields for the other objects. For your case something like this:
public class CustomerInvoiceForm {
private Invoice invoice;
private Customer customer;
// getters and setters
...
}
public ModelAndView postPaymentSuccess(#ModelAttribute("customerInvoiceForm") CustomerInvoiceForm, ...) {
...
}
Then you'd be closer to getting Spring to bind the way you want it to. Spring doesn't use square brackets in the request parameter names to indicate nested fields, though, it uses periods/dots. So instead of "invoice[id]" you would have to use "invoice.id".
If you are unable to change the request parameter names, you are going to have to manually bind the request parameters to your objects.

Resources