Get specific response value from the API in SpringBoot - spring

I am calling one post call and getting the response like below :
Now I want to get the value of the access token and do some logic. How to get the value from the response? Can anyone please help.
Service code of the API.
public String getToken(User user) throws JsonMappingException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(clientId+clientPass);
String plainCreds = clientId+":"+clientPass;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
HttpEntity<String> request=new HttpEntity<String>(headers);
String uri = url+ user.getUser_id()
+ "&password=" + user.getPassword();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST, request, String.class) ;
JsonNode newNode = mapper.readTree(result.getBody());
ObjectNode node = ((ObjectNode) newNode).put("Authentication", "Successful");
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
}

I was able to figure it out.
I used
node.get("access_token")
And it worked!

You can write DTO for response:
public class ResponseSample {
#JsonProperty("access_token")
String accessToken;
....
}
(or deserialize to Map)
and instead calling ResponseEntity<String> result = restTemplate.exchange(...) you can call
ResponseEntity<ResponseSample> result = restTemplate.exchange(..., ResponseSample.class)

Related

Passing Spring pageable in get request

If I send a request from Spring application:
public ResponseEntity<RestResponsePage<Result>> readDocs(
Pageable pageable
) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Authorization", getToken());
String requestUri =
baseAppUrl + "/api/k" + "?page={page}&pageSize={pageSize}&sort={sort}&pageable={pageable}";
Map<String, Object> urlParameters = new HashMap<>();
urlParameters.put("page", Integer.toString(pageable.getPageNumber()));
urlParameters.put("pageSize", Long.toString(pageable.getPageSize()));
urlParameters.put("sort", pageable.getSort());
urlParameters.put("pageable", pageable);
HttpEntity<Void> requestEntity = new HttpEntity<>(requestHeaders);
ResponseEntity<RestResponsePage<Result>> response = restTemplate.exchange( RestResponsePage
requestUri,
HttpMethod.GET,
requestEntity,
new ParameterizedTypeReference<RestResponsePage<Result>>() {},
urlParameters
);
return response;
}
to another Spring application:
#GetMapping("/")
#PageableAsQueryParam
public ResponseEntity<Page<Result>> getAll(
#RequestHeader("Authorization") String token,
#RequestParam("page") Integer page,
#RequestParam("pageSize") Integer pageSize,
#RequestParam("sort") String sort,
#RequestParam("pageable") Pageable pageable
) {
...
}
I have got an error saying:
Resolved [org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable': no matching editors or conversion strategy found]
I know i can pass it seperately by fields like in example above:
page, pageSize etc.
But i want also to send Sort that's is inside Pageable object - that's also not correctly deserialized as a Type Sort.
How can I make it so Pageable is correctly deserialized ?
EDIT:
regarding answer, I added function like:
UriComponentsBuilder withPageable(UriComponentsBuilder builder,
Pageable pageable) {
builder.queryParam("page", pageable.getPageNumber()).queryParam("size",
pageable.getPageSize());
if (pageable.getSort() != null) {
StringBuilder sb = new StringBuilder();
pageable.getSort().forEach(order -> {
sb.append(order.getProperty()).append(",").append(order.getDirection());
});
builder.queryParam("sort", sb.toString());
}
return builder;
}
to make sort properly deserialize.
Do not need to use #RequestParam("pageable").
Pageable Abstract interface for pagination information.
pageSize, pageNumber, sort already provided on the Pageable
Sample Controller
#Controller
public class Controller {
#GetMapping("/...")
public List<...> findAll(Pageable pageable) {
log.debug("pageable: {}", pageable);
// ...
}
}
MockRequetBuilders
RequestBuilder request = MockMvcRequestBuilders.get("/url")
.param("page", "1")
.param("size", "5")
.param("sort", "name,DESC"); // column, ASC|DESC
ResultActions actions = mockMvc.perform(request);
actions.andExpect(...);
RestTemplate
URI uri = UriComponentsBuilder.fromHttpUrl("/url")
.queryParam("page", pageable.getPageNumber())
.queryParam("size", pageable.getPageSize())
.queryParam("sort", pageable.getSort())
.build()
.toUri();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<...> response = restTemplate.exchange(uri, HttpMethod.GET, entity, ...);
https://reflectoring.io/spring-boot-paging/
https://cursos.alura.com.br/forum/topico-no-primary-or-single-unique-constructor-found-for-interface-org-springframework-data-domain-pageable-195442

How to perform an http request to another server from spring boot controller

i want to perform a get request on a server hosted on localhost:80 (for example but could be every host) from my spring boot application hosted on localhost:8080.
For example i want to get an image hosted on locahost:80/image.jpg from my spring application. How can i handle this?
You can use RestTemplate for that.
RestTemplate restTemplate = new RestTemplate();
String uri = localhost:80; // or any other uri
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity<?> result =
restTemplate.exchange(uri, HttpMethod.GET, entity, returnClass);
return result.getBody();
If you want to get images then use following method:
String url = "http://img.championat.com/news/big/l/c/ujejn-runi_1439911080563855663.jpg";
byte[] imageBytes = restTemplate.getForObject(url, byte[].class);
Files.write(Paths.get("image.jpg"), imageBytes);
You will also need to configure ByteArrayHttpMessageConverter in application config:
#Bean
public RestTemplate restTemplate(List<HttpMessageConverter<?>> messageConverters) {
return new RestTemplate(messageConverters);
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
return new ByteArrayHttpMessageConverter();
}
If you want to send a request with spring you can do
//first create e restemplate variable
RestTemplate restTemplate=new RestTemplate();
//you can create and edit header
HttpHeaders header= new HttpHeaders();
header.add("Authorization", "*****************");
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
header.add("Accept", "application/json");
//you can create and edit body to
MultiValueMap<String, String> body= new LinkedMultiValueMap<String, String>();
body.add("grant_type", "client_credentials");
HttpEntity<MultiValueMap<String, String>> requeteHttp =new HttpEntity<MultiValueMap<String, String>>(body, header);
//After you can create a request
ResponseEntity<Response_class> reponse = restTemplate.postForEntity("your api link", requeteHttp , Response_class.class);
//if you want to send a get request you can edit postForEntity to get
About Response_class
if you know the return type of the request, you can create a class and use it here, otherwise you can use string instead
if your request returns a json like this
{
"token_type":"***",
"access_token":"***",
"expires_in":"***",
}
you can create a Response_class controller(class) and call it like we did above otherwise you can use string instead
public class Response_class{
private String token_type;
private String access_token;
private String expires_in;
public Response_class(String token_type, String access_token, String expires_in) {
this.token_type = token_type;
this.access_token = access_token;
this.expires_in = expires_in;
}
public Response_class() {
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
}
You can use WebClient:
byte[] image = WebClient.create("locahost:80/image.jpg")
.get()
.accept(MediaType.IMAGE_JPEG)
.retrieve()
.bodyToMono(byte[].class)
.block();

Problem while uploading MultiValueMap using FeignClient for MultipartFile receiver API

I am facing issues while sending MultipartFile from one service to another service.
API which I want to call is,
#PostMapping(value = "/posts/{postId}/comments/{commentId}/attachments")
#JsonView(CaseJsonView.ClientWithComments.class)
public ResponseEntity<?> createCommentAttachment(#PathVariable final String postId, #PathVariable final String commentId, #RequestParam("payload") final MultipartFile multipartFile, #RequestParam final String filename, final HttpServletRequest request) throws JsonProcessingException {
try {
FileUtils.writeByteArrayToFile(new File("C:\\CODE\\data\\" + filename), multipartFile.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
Here empty file is getting created when I call this API like below,
FeignClient
#FeignClient(name = "post-service")
public interface CommentClient {
#RequestMapping(method = RequestMethod.POST, value = "/posts/{postId}/comments/{id}/attachments?filename={filename}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
void storeCommentAttachmentPayload(#PathVariable("postId") String postId, #PathVariable("id") String id, #RequestBody MultiValueMap<String, Object> map, #PathVariable("filename") String filename);
}
And I am using this FeignClient like below,
public void sendAttachment() {
//Adding only attachment code.
// Here attachmentClient is some other FeignClient which is returning attachment.
final Resource resource = attachmentClient.getAttachmentPayloadById(attachementId);
final MultipartFile multipartFile = new InMemoryMultipartFile(filename, filename,
mimeType, IOUtils.toByteArray(resource.getInputStream()));
final MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
final ByteArrayResource byteArrayResource = new
ByteArrayResource(multipartFile.getBytes()) {
#Override
public String getFilename() {
return filename == null ? "" : filename;
}
};
map.add(PAYLOAD, byteArrayResource);
commentService.storeCommentAttachmentPayload(postId commentId, map, filename);
}
Observation:
Here my observation is that when I save files on disk from this method, all data is shown properly.
But at the receiver end empty file is saved.
Another observation is that somehow byte array size is less at the receiver end than the sender end. Check the below image,
One more observation is that text files are uploaded properly.
So finally I found a solution to my problem. Instead of uploading a file using FeignClient, I am uploading using RestTemplate as below,
final List<ServiceInstance> postServiceInstances = discoveryClient.getInstances("post-service");
if (postServiceInstances != null && !postServiceInstances.isEmpty()) {
final HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<MultiValueMap<String, Object>>(multiValuMap);
final ResponseEntity<String> response = restTemplate
.postForEntity(postServiceInstances.get(0).getUri() + "/posts/" + postId + "/comments/" + commentId + "/attachments?filename=" + filename, entity, String.class);
if (response.getStatusCode() != HttpStatus.CREATED) {
throw new Exception("Exception from post-service: " + response.getStatusCode());
}
} else {
throw new Exception("No post-service instance found");
}
Not actually a perfect solution but it is solving my purpose.
Also, I have added RestTemplate Interceptor which adds a token in my request.
Still, the solution using FeignClient will be appreciated.

RestTemplate.exchange doesn't work properly. Missing params thrown

I've got 2 aplication one calling another. In the first one I have
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
parameters.add("stationFrom", stationfrom);
parameters.add("stationTo", stationto);
parameters.add("operator", 5);
parameters.add("dateTimeFrom", sdfnative.format(sdfeskm.parse(departuredate)));
parameters.add("dateTimeTo", sdfnative.format(sdfeskm.parse(departuredate).getTime() + 60*60*1000));
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(parameters, headers);
jsonTrain = restTemplate.exchange(url, HttpMethod.GET, request, String.class).toString();
the url is defined as global http://ip:8090/connection/search
When I'm looking at the request I can see that every parameter has it's proper value, but in the restTemplate.exchange line I got error "Parameter stationFrom is missing"
My endpoint on provided IP looks like :
#GetMapping(value = "/connection/search")
public ResponseEntity<String> getConnection(#RequestParam(value = "stationFrom") int stationFrom,
#RequestParam(value = "stationTo") int stationTo,
#RequestParam(value = "operator") int operator,
#RequestParam(value = "dateTimeFrom") String dateTimeFrom,
#RequestParam(value = "dateTimeTo") String dateTimeTo) throws JSONException
I don't know why it throws me this error if stationFrom has for example value 40 and I can see it in debug/logs
Of course calling provided endpoint from postman, with the same data gives me expected result :)
You are passing the query parameters (RequestParams) as headers.
Check the following example how to pass RequestParams:
public void findUserById()
{
String username = "chathuranga";
String password = "123";
Integer userId = 1;
String url = "http://localhost:" + port + "/users/" + userId;
//setting up the HTTP Basic Authentication header value
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
HttpHeaders requestHeaders = new HttpHeaders();
//set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
//request entity is created with request headers
HttpEntity<AddUserRequest> requestEntity = new HttpEntity<>(requestHeaders);
//adding the query params to the URL
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("name", "chathuranga")
.queryParam("email", "chathuranga.t#gmail.com");
ResponseEntity<FindUserResponse> responseEntity = restTemplate.exchange(
uriBuilder.toUriString(),
HttpMethod.GET,
requestEntity,
FindUserResponse.class
);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
System.out.println("response received");
System.out.println(responseEntity.getBody());
} else {
System.out.println("error occurred");
System.out.println(responseEntity.getStatusCode());
}
}

Spring RestTemplate Handling Multiple Responses

I'm consuming a restful service, What I observed is based on the request I see multiple responses for the same end point.
For Ex : I request a GET call with the some parameters for a PDF document.
if the response is good and the content type is application/pdf its giving a pdf document.
if the document is not available, the content type is application/xml and the response is giving the error code, error description.
Any input is much appreciated !
Thanks,
Sudheer.
You can use the ResponseEntity class of Spring, you can set the class to return the object what you want. You can change the content type, and everything you want.
here there is an example of file
#RequestMapping(value = URIConstansts.GET_FILE, produces = { "application/json" }, method = RequestMethod.GET)
public #ResponseBody ResponseEntity getFile(#RequestParam(value="fileName", required=false) String fileName,HttpServletRequest request) throws IOException{
ResponseEntity respEntity = null;
byte[] reportBytes = null;
File result=new File("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
if(result.exists()){
InputStream inputStream = new FileInputStream("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
String type=result.toURL().openConnection().guessContentTypeFromName(fileName);
byte[]out=org.apache.commons.io.IOUtils.toByteArray(inputStream);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("content-disposition", "attachment; filename=" + fileName);
responseHeaders.add("Content-Type",type);
respEntity = new ResponseEntity(out, responseHeaders,HttpStatus.OK);
}else{
respEntity = new ResponseEntity ("File Not Found", HttpStatus.OK);
}
return respEntity;
}
Here there is an example of Json
#ResponseBody ResponseEntity<? extends AbstractResponse> createUser(#RequestBody String requestBody) {
if(!valid(requestBody) {
ErrorResponse errResponse = new ErrorResponse();
//populate with error information
return new ResponseEntity<ErrorResponse> (errResponse, HTTPStatus.BAD_REQUEST);
}
createUser();
CreateUserSuccessResponse successResponse = new CreateUserSuccessResponse();
// populate with more info
return new ResponseEntity<CreateUserSuccessResponse> (successResponse, HTTPSatus.OK);
}

Resources