Rest Template : Mapping attribute in request and response - java

I have to develop an api using Rest Template , The api I am calling return a complex object with lots of attributes ,The FileResponse object in my api needs only few attributes from the api I am calling
ResponseEntity responseEntity = restTemplate.exchange(URL, HttpMethod.POST, entity, FileSearchResponse.class);
Do I have to map all attributes of the complex object or few which I need will work

Related

How to retrieve the URL of a RequestEntity obtained from RequestEntity.post(String, Object...)

I'm using Spring Boot 2.6.1 with Spring Web MVC, and in my controller, I want to get the received RequestEntity instead of only the request body, because I have to use information such as the URL.
When I want to test my controller, I build a RequestEntity with the following code:
RequestEntity<String> r = RequestEntity.post("http://www.example.com/{path}", "myPath").body("");
Now, I don't know how to retrieve the URL information from that RequestEntity:
r.getUrl() throws an UnsupportedOperationException because there is no URL in the RequestEntity.
When looking at the code in RequestEntity.body(String), I see that the returned object is an UriTemplateRequestEntity extending RequestEntity, but this object seems to always have an null URL according to its constructor. Only the uriTemplate, uriVarsArray and uriVarsMap attributes are set. But these attributes are not part of RequestEntity.
How can I retrieve the URL information from r, without casting it to an UriTemplateRequestEntity? Is that a bug in RequestEntity.getUrl() I should report?
NB: My workaround is the following:
RequestEntity<String> r = RequestEntity.post(URI.create(format("http://www.example.com/%s", "myPath"))).body("");
or
RequestEntity<String> r = RequestEntity.post(URI.create("http://www.example.com/{path}".replaceAll("\\{path\\}", "myPath"))).body("");
Use HttpServletRequest in controller parameter like below:
#GetMapping("/")
public String test(HttpServletRequest httpReq){
String url=httpReq.getRequestURL().toString();
// More code
}

RestTemplate & multipart/form-data response

I need to write a REST Client using RestTemplate that will call the following endpoint:
#RequestMapping(value = "/{documentID}", method = RequestMethod.GET, produces = "multipart/form-data")
#ResponseBody
ResponseEntity<MultiValueMap<String, Object>> getDocument(#PathVariable("documentID") long documentID);
This endpoint builds multipart/form-data response including a document (InputStreamResource) and the document's info (JSON) parts.
However, I receive the following exception:
org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [interface org.springframework.util.MultiValueMap] and content type [multipart/form-data;boundary=f9yLuCpxZoS4W5lu5iYivlD8fIo28BBMr5PXzu;charset=UTF-8]
I have FormHttpMessageConverter (that is supposed to process form data to/from a MultiValueMap) in my RestTemplate, but it still doesn't work because according to the official docs this converter can't read multipart/form-data (only write):
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/FormHttpMessageConverter.html
This endpoint works fine via Postman, returning both JSON and File parts, so I'm wondering which kind of magic I'm missing to make it work using RestTemplate.
Is it possible to write a REST client to process multipart/form-data response and if yes, which converter should be used for such messages, do I have to write a custom HttpMessageConverter?
I collided with the same case and wrote a simple example(MultipartMessageConverter). This example allows to convert a request(resource and JSON) to one DTO model as you can se in test. A model can consist Resource
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MultiPartMessageConverter(objectMapper));
final ResponseEntity<ResultModel> responseEntity = restTemplate.getForEntity("http://localhost:" + randomServerPort + "/test", ResultModel.class);
final ResultModel resultModel = responseEntity.getBody();
Assertions.assertNotNull(resultModel);
Assertions.assertEquals(2, resultModel.secondModel.size());
Assertions.assertEquals("Param1.Value", resultModel.firstModel.param1);
Assertions.assertEquals("Param2.Value", resultModel.firstModel.param2);

Spring webhook endpoint get entire body as well as pojo

I am making an application using spring, and I have a webhook endpoint as shown below
#PostMapping("/paypal")
fun paypalMapping(
#RequestHeader headers: Map<String, String>,
#RequestBody paypalOrder: PaypalOrder
) {
// Stuff in here
}
Now, the problem I have with this is the paypal Event.validateReceivedEvent requires the entire webhook body as a string, and as you can see above, I map it to a POJO I made, meaning I do not have the entire webhook body as a string. I tried simply adding another #RequestBody body:String parameter to the method, and that just came with an error about not being able to find the body.
Thanks
You can't bind the request body twice unfortunately, you can only use the #RequestBody once. What I'd do is to bind it as a String and deserialize manually:
#PostMapping("/paypal")
fun paypalMapping(
#RequestHeader headers: Map<String, String>,
#RequestBody body: String
) {
// Stuff in here
}

Is there a standard way in Spring to pass a body with a DELETE request to a REST endpoint?

I am implementing a Spring client for an existing REST API and I need to invoke a DELETE while, at the same time, passing an access token in the request body, like this:
{
"access_token": "..."
}
The problem is that, using the method that works for POST, the transmitted body is empty (I have intercepted the request body and made sure) and I cannot be authorised without this access token. This is what I am doing:
RestTemplate restTemplate = new RestTemplate();
UserRequest ur = new UserRequest(access_token);
HttpEntity<UserRequest> entity = new HttpEntity<>(ur);
restTemplate.delete(url, entity);
I have no control over the API itself, so I don't have the option of passing the token as url parameter.
Is there a way to do this in Spring, or do I have to build my own HttpUrlConnection like described for instance in this SO answer?
In the RestTemplate object in Spring there's an exchange method.
The parameters are :
the url
the method, in your case HttpMethod.DELETE
the entity (with the body you have to transmit)
the response type
some object you could pass
Hope this help

SpringBoot RestController generic POST type

I'm experimenting with building microservices using Spring Boot.
I have a back-end API that receives ResponseEntity POST requests and processes it (saving to database etc). Where Data is an Object of a self-created class.
Now I have a top-level API (that handles authentication,..). The end-users will communicate with the back-end services through this top-level API. So this API basically just has to forward all the requests to the right back-end api's.
In this top API I don't want to need to include all my classes (e.g. the Data class in this case) and I would rather just send it as String json data or something. So I tried this:
#RequestMapping(method = RequestMethod.POST, value="/data")
ResponseEntity<String> createUnit(#RequestBody String data) {
URI uri = util.getServiceUrl("dataservice");
String url = uri.toString() + "/data";
ResponseEntity<String> result = restTemplate.postForEntity(url, data, String.class);
return new ResponseEntity<String>(result.getBody(), HttpStatus.OK);
}
But this results in an org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type.
So my question is, is there a way to forward these requests to my back-end without the need to include all my Object classes in my API? I figured this should be able since this is the same as when a web-browser sends requests in json format without knowing what kind of Object the data actually is.
The back-end handling looks like this:
#RequestMapping(method = RequestMethod.POST, value="/data")
ResponseEntity<Data> saveData(#RequestBody Data data) {
//Some code that processes the data
return new ResponseEntity<Data>(dataProcessed, HttpStatus.OK);
}
When posting the String to the backend service you have to specify the Content-Type header so Spring knows which HttpMessageConverter to use to deserialize the Data object.
With RestTemplate you can specify the header like this:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(data, headers);
restTemplate.postForEntity(url, entity, responseType);
Even though the question was already answered, I'll show another way I managed to solve the problem.
I used type Object instead of String:
#RequestMapping(method = RequestMethod.POST, value="/data")
ResponseEntity<Object> createUnit(#RequestBody Object data) {
URI uri = util.getServiceUrl("dataservice");
String url = uri.toString() + "/data";
ResponseEntity<Object> result = restTemplate.postForEntity(url, data, Object.class);
return new ResponseEntity<Object>(result.getBody(), HttpStatus.OK);
}

Categories