TraceID for a request is not travelling between services - spring

I am calling a microservice from a microservice and expecting the traceID (given by sleuth) initiated from base service should travel to the called services as implanted sleuth with zipkin.
Here is the call to the service
RestTemplate restTemplate = new RestTemplate();
logger.info("ApplicationController: controllerMessage() called: " + properties.getType() +
" " + properties2.getMode());
String uri = "http://localhost:8089/poc1/message";
//String uri = "http://google.com";
HttpHeaders headers = new HttpHeaders();
//headers.add("Authorization", authToken);
HttpEntity request = new HttpEntity(headers);
ResponseEntity<String> response = restTemplate.exchange(
uri,
HttpMethod.GET,
request,
String.class
);
Expecting that the same traceID printed in the logs of above service will be printed in the logs of called service. In this case, same trace id should print in the logs of http://localhost:8089/poc1/message. However this is not happening.
Using 2.7.5 version of spring boot and 2021.0.4 of spring cloud.
Any clue what is wrong here?
Expecting the same traceID generated by the initial request should print in the logs of called service.

You're creating RestTemplate via new. Please create it as a bean and inject it to your code.
#Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
We're writing it in the docs with a big exclamation mark here https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/integrations.html#sleuth-http-client-rest-template-integration
Let me paste that for your convenience
You have to register RestTemplate as a bean so that the interceptors get injected. If you create a RestTemplate instance with a new keyword, the instrumentation does NOT work.

Related

How to call service in spring boot

How can I call a service like the following in the spring-boot using the RestTemplate class ???
service api : https://192.168.100.20/api/index.php?e=/Base/User/Filter&apikey=a27209c3-edd6-6384-e1cb-1bef2df28&salt=1747229424&signature=JFH44DtCHdSV%2BJBvajNQBsiak07nPVyFb7ZYKj%2BqTno%3D
Something like this would work, but I'm not sure what exactly is your goal.
private RestTemplate template = new RestTemplate();
private String url = "https://192.168.100.20/api/index.php?e=/Base/User/Filter&apikey=a27209c3-edd6-6384-e1cb-1bef2df28&salt=1747229424&signature=JFH44DtCHdSV%2BJBvajNQBsiak07nPVyFb7ZYKj%2BqTno%3D";
template.getForEntity(url, String.class);
The first thing you should try to find is which Http Verb the service you want to call use.
GET, PUT, etc.
When you know which HTTP verb you have to use, you can use RestTemplate with the http verb of your service.
For GET
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl =
"https://192.168.100.20/api/index.php?e=/Base/User/Filter&apikey=a27209c3-edd6-6384-e1cb-1bef2df28&salt=1747229424&signature=JFH44DtCHdSV%2BJBvajNQBsiak07nPVyFb7ZYKj%2BqTno%3D";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl, String.class);
For POST
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);

Why im getting Exception- Not enough variables available to expand in Spring Rest URI call?

im working on a rest API call related to Payments. But i encountered with an exception. I know this comes due to setting parameters to the rest uri.
String uri = "https://test-gateway.mastercard.com/api/rest/version/52/merchant/{merchantId}/order/{orderId}/transaction/{transactionId}";
LinkedMultiValueMap<String, String> uriVars = new LinkedMultiValueMap<>();
uriVars.add("merchantId", _paymentInstrument.getAcquirerMid());
uriVars.add("orderId", _paymentInstrument.getOrderId().toString());
uriVars.add("transactionId", _paymentInstrument.getTargetTransactionId().toString());
String uri = UriComponentsBuilder.fromHttpUrl(url)
.queryParams(uriVars).build().toUriString();
VoidRequest voidRequest =
createVoidRequest(_paymentInstrument.getTargetTransactionId());
HttpEntity<VoidRequest> requestEntity = new HttpEntity<>(voidRequest, headers);
ResponseEntity<TransactionResponse> responseEntity = restTemplate.exchange(uri, HttpMethod.PUT, requestEntity, TransactionResponse.class);
Exception im getting is Using RestTemplate in Spring. Exception- Not enough variables available to expand "merchantId".

spring boot application periodic post request via resttemplate in json

Below is my spring boot code snippet to post json data to server url every few min to tell that I am alive and running(which loads my json input data to db). purpose of this post request is to update the status on application monitoring tool.
What could be the right approach to implment this behaviour in my spring boot app? Is their any decorator api to do such post request to url, every few miuntes through out the application.? how can I know the time of successful post request to do next post request ? Please help me. Thanks in advance.
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
Why don't you use the #Scheduled annotation? This will seutes.nd your REST request every 3 minutes...
#Component
public class Heartbeater {
#Scheduled(fixedDelay = 180000)
public void heartbeat() {
// Your code is below...
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
}

RestTemplate call returns 401 Unauthorized

Background
I am trying to consume a REST endpoint hosted on IBM Cloud API from my SpringBoot application using RestTemplate. I am using the following snippet to make the call:
RestTemplate send = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setCacheControl(CacheControl.noCache());
headers.set("x-ibm-client-id", clientId);
headers.set("x-ibm-client-secret", clientSecret);
HttpEntity<BodyEntity> httpEntity = new HttpEntity<>(bodyEntity, headers);
send.exchange(ENDPOINT_URL, HttpMethod.POST, httpEntity, Object.class);
I used the following snippet to configure RestTemplate
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
Problem
Using this snippet, when the call is made I receive 401 Unauthorized. When I made the same call using Postman, I received correct response from server without any problem.
Since I received 401 response code I set to further investigate the request by logging headers and body and other parts of request.
I implemented ClientHttpRequestInterceptor to log outgoing requests to further debug the issue and added this interceptor to my RestTemplate config as follows:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// new code
builder.interceptors(new LoggingClientHttpRequestInterceptor());
return builder.build();
}
After making the request again, I could see in the log that the outgoing call contained all details as it should e.g. Headers and Body were correct.
After this, I changed the whole thing to use Apache HTTP Client as follows:
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(URL);
String reqString = "BODY";
httpPost.setEntity(new StringEntity(reqString, ContentType.APPLICATION_JSON));
httpPost.setHeader("accept", "application/json");
httpPost.setHeader("content-type", "application/json");
httpPost.setHeader("cache-control", "no-cache");
httpPost.setHeader("x-ibm-client-id", clientId);
httpPost.setHeader("x-ibm-client-secret", clientSecret);
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
System.out.println("Response status: " + response.getStatusLine());
HttpEntity entity1 = response.getEntity();
System.out.println("Response :" + entity1.toString());
} finally {
response.close();
}
Using the snippet above, I executed the request and received correct response.
Question
Why RestTemplate call returns and error whereas HttpClient returns correct response?
Do I need to further configure RestTemplate?
What have I missed?

Authentication for POST REST API with spring restTemplate

I want to use Spring RESTTemplate to post an Object to a web server and get one back.
Here the piece of code:
String authStringEncoded =
Base64.getEncoder().encodeToString
("582f3e4a9e933168ea1048e6:98c6f2736c5f02279d767ce7ddfe7e5d".getBytes("utf-8"));
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + authStringEncoded);
HttpEntity<String> request = new HttpEntity<String>(headers);
RestTemplate rt = new RestTemplate();
rt.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
rt.getMessageConverters().add(new StringHttpMessageConverter());
String uri = new String(REGISTERING_NEW_DEVICES.replace("{devicetype-id}", KIT_TYPE_ID));
TdkDevice deviceC3DF86B = new TdkDevice();
deviceC3DF86B.setId("C3DF86B");
deviceC3DF86B.setPal("44CFFFC9D5F8E8B2F36");
DeviceRegistration deviceRegistration = new DeviceRegistration();
deviceRegistration.getIds().add(deviceC3DF86B);
rt.postForObject(uri, HttpMethod.POST, request, deviceRegistration, DeviceRegistration.class);
But I got a compilation error:
The method postForObject(String, Object, Class<T>, Object...) in the type RestTemplate is not applicable for the arguments (String, HttpMethod, HttpEntity<String>, DeviceRegistration,
Class<DeviceRegistration>)
Your service call should be like following:
rt.postForObject(uri, request, DeviceRegistration.class);
According to spring RestTemplate api, postForObject method's parameters should be following:
Parameters:
url - the URL
request - the Object to be POSTed (may be null)
responseType - the type of the return value
uriVariables - the variables to expand the template
API Reference

Resources