Accepting Hashmap as a body for the POST call - spring

I have to write a procedure which will accept body in Hashmap format.
I have created HttpEntity with Hashmap values & headers.
public <T> void doPOSTRequest(String url, T body, HttpHeaders headers) throws JsonProcessingException {
HttpEntity<T> request = new HttpEntity<T>(body,headers);
System.out.println("Printing Request :" + request);
ResponseEntity<String> response = null;
//Calling POST Method
//response=restTemplate.postForObject(url,request,String.class);
response=restTemplate.exchange(url, HttpMethod.POST,request,String.class);
System.out.println(response);
}
I am facing below exception :
Exception in thread "main"
org.springframework.web.client.RestClientException: No
HttpMessageConverter for [java.util.HashMap] at
org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:957)
at
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:733)
at
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)
at
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579)
at Com.RESTRequest.doPOSTRequest(RESTRequest.java:39) at
Com.GenericREST.main(GenericREST.java:30)

Try using MultiValueMap instead of Generic like this
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<MultiValueMap<String, Object>>(parameters, headers);
Full block:
public <T> void doPOSTRequest(String url, T body, HttpHeaders headers) throws JsonProcessingException {
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(body,headers);
System.out.println("Printing Request :" + request);
ResponseEntity<String> response = null;
//Calling POST Method
//response=restTemplate.postForObject(url,request,String.class);
response=restTemplate.exchange(url, HttpMethod.POST,request,String.class);
System.out.println(response);
}

Related

Spring Boot RestTemplate: Bad request when directly copying from postman

So I have an API request where I am copying the details directly from postman where it works. I am however getting a bad request error.
#Service
public class GraphApiService {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Autowired
RestTemplate restTemplate;
#Autowired
Constants constants;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public ResponseEntity<String> getAccessTokenUsingRefreshToken(Credential cred) throws IOException{
try {
//https://learn.microsoft.com/en-us/graph/auth-v2-user
// section 5. Use the refresh token to get a new access token
String url = "url";
JSONObject body = new JSONObject();
body.put("grant_type", "refresh_token");
body.put("client_id", "clientid");
body.put("scope","User.Read offline_access Files.Read Mail.Read Sites.Read.All");
body.put("redirect_uri", "http://localhost");
body.put("client_secret","secret");
body.put("refresh_token", "token");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> request = new HttpEntity<String>(body.toString(), headers);
ResponseEntity<String> response= restTemplate.postForEntity(url, request,String.class);
return response;
}
catch(HttpClientErrorException e){
logger.error(e.getResponseBodyAsString());
logger.error(e.getMessage());
return null;
}
}
I would appreciate any help. The bad request error message from microsoft graph isn't a descriptive one that will help
You're sending JSON payload with FORM_URLENCODED header.
Either you need to check if API accepts json payload, if so you need to change content-type to application/json or you can post form data as follows.
public ResponseEntity<String> getAccessTokenUsingRefreshToken(Credential cred) throws IOException{
try {
//https://learn.microsoft.com/en-us/graph/auth-v2-user
// section 5. Use the refresh token to get a new access token
String url = "url";
MultiValueMap<String, String> multiValueMap= new LinkedMultiValueMap<String, String>();
multiValueMap.add("grant_type", "refresh_token");
multiValueMap.add("client_id", "clientid");
//.....
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(multiValueMap, headers);
ResponseEntity<String> response= restTemplate.postForEntity(url, request, String.class);
return response;
}catch(HttpClientErrorException e){
logger.error(e.getResponseBodyAsString());
logger.error(e.getMessage());
return null;
}
}

Spring RestTemplate, getting junk response when http status code is 404

I am writing a rest proxy (it exposes the API and delegates call to other server) and it works fine for the normal case and also for 500 http status code, we get the response from the rest client.
But when we get 404 status code, the Rest API server returns the message but we get junk values from the RestTemplate. We need to pass the same response to other API user but cannot get the same response.
Message returned from REST API Server:
{
"status_code":"0",
"error":{
"code":"404",
"description":"Source not found"
}
}
Getting the below response by RestTemplate client:
Not able to paste the content, attaching the screen shot of the response.
Please see the code below.
#RequestMapping(value = "/api/**")
public #ResponseBody String apiProxy(#RequestBody String body, HttpMethod method, HttpServletRequest request,
HttpServletResponse response) throws URISyntaxException {
RestTemplate restTemplate = new RestTemplate(
new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
restTemplate.setInterceptors(Collections.singletonList(new RestClientLoggingInterceptor()));
restTemplate.setErrorHandler(new CustomResponseErrorHandler());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
HttpHeaders httpHeaders = new HttpHeaders();
Enumeration<String> headers = request.getHeaderNames();
String headerName = null;
String headerValue = null;
while (headers.hasMoreElements()) {
headerName = headers.nextElement();
headerValue = request.getHeader(headerName);
httpHeaders.set(headerName, headerValue);
}
HttpEntity<String> httpEntity = new HttpEntity<String>(body, httpHeaders);
URI uri = new URI(ServerProtocol, null, ServerDomain, Integer.valueOf(ServerPort),
request.getRequestURI(), request.getQueryString(), null);
ResponseEntity<String> responseEntity = null;
try {
responseEntity = restTemplate.exchange(uri, method, httpEntity, String.class);
} catch (RestClientResponseException e) {
response.setStatus(e.getRawStatusCode());
return e.getResponseBodyAsString();
}
response.setStatus(responseEntity.getStatusCode().value());
return responseEntity.getBody();
}
ResponseErrorHandler Class
public class CustomResponseErrorHandler extends DefaultResponseErrorHandler {
private static final Logger logger = LogManager.getLogger(CustomResponseErrorHandler.class);
#Override
public void handleError(ClientHttpResponse response) throws IOException {
logger.error("Response error: {} {}", response.getStatusCode(), response.getStatusText());
}
}
RestClientLoggingInterceptor Class
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
ClientHttpResponse response = execution.execute(request, body);
logger.debug("request method:" + request.getMethod());
logger.debug("request URI:" + request.getURI());
logger.debug("request headers:" + request.getHeaders());
logger.debug("request body:" + new String(body, Charset.forName("UTF-8")));
logger.debug("response status code:" + response.getStatusCode());
logger.debug("response headers:" + response.getHeaders());
logger.debug("response body:" + IOUtils.toString(response.getBody(), "UTF-8"));
return response;
}
Thanks
Cannot parse gzip encoded response with RestTemplate from Spring-Web
This was helpful to me for this same issue. You can try this out.

How to request POST using RestTemplate, authorized using user password

Can some one tell how I can use RestTemplate to POST a HttpEntity object using Authorization. I am using below code in test application
Client Side :
public class FifthWay extends Thread {
public void run() {
String plainCreds = "anuj:khare";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
HttpEntity<String> postRequest = new HttpEntity<String>("FifthWay",headers);
RestTemplate rt = new RestTemplate();
rt.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
rt.getMessageConverters().add(new StringHttpMessageConverter());
String postUri = new String("http://169.194.48.182:8080/trade-capture-service/deals/persist");
ResponseEntity<String> responseForPost = rt.exchange(postUri,HttpMethod.POST, postRequest, String.class);
String responseStringForPost = responseForPost.getBody();
System.out.println(responseStringForPost);
}
}
Server side :
#Controller
#RequestMapping("/deals")
public class RestController {
...
...
#RequestMapping(value = "/check", method = RequestMethod.GET)
public #ResponseBody
String justACheck() {
System.out.println("It Works");
return "It works";
}
Getting errors like :
Exception in thread "Thread-4" org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
OR
Exception in thread "Thread-4" org.springframework.web.client.HttpClientErrorException: 400 Bad Request
Please help
Here is the example of RestTemplate exchange :
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
final HttpEntity entity = new HttpEntity(restCanvas, requestHeaders);
return restTemplate.exchange(canvasAddUrl + value, HttpMethod.POST, entity, Integer.class);
Here canvasAddURL is the URL you wish to call with context-path. If you want to add a cookie to it, lemme know, i have removed that code as it is most of the time not necessary. The return value for this is ResponseEntity<Integer> . Check it out.

Session closed error when performing subsequence requests to client via Spring RestTemplate

I'm trying to use spring rest template to do a post request to login in.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
LinkedMultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
mvm.add("LoginForm_Login", "login");
mvm.add("LoginForm_Password", "password");
ResponseEntity<String> result = restTemplate.exchange(uriDWLogin, HttpMethod.POST, requestEntity, String.class);
all goes well, but when I try to send a second request, It generates an error saying :
Business Manager closes your session after 15 minutes
What can I do to solve this problem ?!
When you receive the response in your first request you should store your session id which is received via cookie. You will retrieve it in a set-cookie response header which you can get via:
//first request
RestTemplate template = new RestTemplate();
ResponseEntity<String> forEntity = template.getForEntity("http://google.bg", String.class);
forEntity.getHeaders().get("Set-Cookie").stream().forEach(System.out::println);
then in every subsequent request you should set the Cookie request header with the values received in the first request:
//subsequent request
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie",cookies.stream().collect(Collectors.joining(";")));
HttpEntity<String> entity = new HttpEntity<String>(headers);
restTemplate.exchange("http://url", HttpMethod.POST, entity, String.class);
I have a StaticRestTemplate class, this way I get the same RestTemplate instance.
public class StaticRestTemplate {
public volatile static RestTemplate rest = new RestTemplate();
public static volatile String jsessionid = "";
// This way, I can test on local or server just by changing one URL.
public static volatile String baseURL = "http://192.168.178.60:8080/";
}
Login code :
public static RestTemplate rest = new RestTemplate();
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StaticRestTemplate.jsessionid = rest.execute(StaticRestTemplate.baseURL+"j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + email + "&j_password=" + password).getBytes());
}
}, new ResponseExtractor<String>() {
#Override
public String extractData(ClientHttpResponse response) throws IOException {
List<String> cookies = response.getHeaders().get("Cookie");
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
return null;
}
Now, my JsessionID is saved, and I can use it directly for subsequent requests this way :
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
// This is where I add the cookie value
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders);
HttpEntity<String> rssResponse = rest.exchange(
StaticRestTemplate.baseURL+"dashboard",
HttpMethod.GET,
requestEntity,
String.class);
StaticRestTemplate.replyString = rssResponse.getBody();
return StaticRestTemplate.replyString;
If there are doubts, let me know.
You can try to disable cookie management with factory for your RestTemplate:
HttpClient httpClient = HttpClientBuilder.create()
.disableCookieManagement()
.useSystemProperties()
.build();
factory.setHttpClient(httpClient);

How to set an "Accept:" header on Spring RestTemplate request?

I want to set the value of the Accept: in a request I am making using Spring's RestTemplate.
Here is my Spring request handling code
#RequestMapping(
value= "/uom_matrix_save_or_edit",
method = RequestMethod.POST,
produces="application/json"
)
public #ResponseBody ModelMap uomMatrixSaveOrEdit(
ModelMap model,
#RequestParam("parentId") String parentId
){
model.addAttribute("attributeValues",parentId);
return model;
}
and here is my Java REST client:
public void post(){
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("parentId", "parentId");
String result = rest.postForObject( url, params, String.class) ;
System.out.println(result);
}
This works for me; I get a JSON string from the server side.
My question is: how can I specify the Accept: header (e.g. application/json,application/xml, ... ) and request method (e.g. GET,POST, ... ) when I use RestTemplate?
I suggest using one of the exchange methods that accepts an HttpEntity for which you can also set the HttpHeaders. (You can also specify the HTTP method you want to use.)
For example,
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
I prefer this solution because it's strongly typed, ie. exchange expects an HttpEntity.
However, you can also pass that HttpEntity as a request argument to postForObject.
HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.postForObject(url, entity, String.class);
This is mentioned in the RestTemplate#postForObject Javadoc.
The request parameter can be a HttpEntity in order to add additional
HTTP headers to the request.
You could set an interceptor "ClientHttpRequestInterceptor" in your RestTemplate to avoid setting the header every time you send a request.
public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {
private final String headerName;
private final String headerValue;
public HeaderRequestInterceptor(String headerName, String headerValue) {
this.headerName = headerName;
this.headerValue = headerValue;
}
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set(headerName, headerValue);
return execution.execute(request, body);
}
}
Then
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new HeaderRequestInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(interceptors);
If, like me, you struggled to find an example that uses headers with basic authentication and the rest template exchange API, this is what I finally worked out...
private HttpHeaders createHttpHeaders(String user, String password)
{
String notEncoded = user + ":" + password;
String encodedAuth = Base64.getEncoder().encodeToString(notEncoded.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic " + encodedAuth);
return headers;
}
private void doYourThing()
{
String theUrl = "http://blah.blah.com:8080/rest/api/blah";
RestTemplate restTemplate = new RestTemplate();
try {
HttpHeaders headers = createHttpHeaders("fred","1234");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
}
catch (Exception eek) {
System.out.println("** Exception: "+ eek.getMessage());
}
}
Calling a RESTful API using RestTemplate
Example 1:
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters()
.add(new MappingJackson2HttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic XXXXXXXXXXXXXXXX=");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
restTemplate.getInterceptors()
.add(new BasicAuthorizationInterceptor(USERID, PWORD));
String requestJson = getRequetJson(Code, emailAddr, firstName, lastName);
response = restTemplate.postForObject(URL, requestJson, MYObject.class);
Example 2:
RestTemplate restTemplate = new RestTemplate();
String requestJson = getRequetJson(code, emil, name, lastName);
HttpHeaders headers = new HttpHeaders();
String userPass = USERID + ":" + PWORD;
String authHeader =
"Basic " + Base64.getEncoder().encodeToString(userPass.getBytes());
headers.set(HttpHeaders.AUTHORIZATION, authHeader);
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> request = new HttpEntity<String>(requestJson, headers);
ResponseEntity<MyObject> responseEntity;
responseEntity =
this.restTemplate.exchange(URI, HttpMethod.POST, request, Object.class);
responseEntity.getBody()
The getRequestJson method creates a JSON Object:
private String getRequetJson(String Code, String emailAddr, String name) {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.createObjectNode();
((ObjectNode) rootNode).put("code", Code);
((ObjectNode) rootNode).put("email", emailAdd);
((ObjectNode) rootNode).put("firstName", name);
String jsonString = null;
try {
jsonString = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(rootNode);
}
catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonString;
}
Short solution without HttpHeaders creating:
RequestEntity<Void> request = RequestEntity.post(URI.create(url))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
// any other headers
.header("PRIVATE-TOKEN", "token")
.build();
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
return response.getBody();
UPDATE: but in case specific headers HttpHeaders become simple:
RequestEntity.post(URI.create(AMOCRM_URL + url))
.contentType(MediaType.APPLICATION_JSON)
.headers(
new HttpHeaders() {{
setBearerAuth(getAccessToken());
}})
.body(...)
Here is a simple answer. Hope it helps someone.
import org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
public String post(SomeRequest someRequest) {
// create a list the headers
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new HttpHeaderInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));
interceptors.add(new HttpHeaderInterceptor("ContentType", MediaType.APPLICATION_JSON_VALUE));
interceptors.add(new HttpHeaderInterceptor("username", "user123"));
interceptors.add(new HttpHeaderInterceptor("customHeader1", "c1"));
interceptors.add(new HttpHeaderInterceptor("customHeader2", "c2"));
// initialize RestTemplate
RestTemplate restTemplate = new RestTemplate();
// set header interceptors here
restTemplate.setInterceptors(interceptors);
// post the request. The response should be JSON string
String response = restTemplate.postForObject(Url, someRequest, String.class);
return response;
}

Categories

Resources