I have a rest Controller where i am trying to get the Token from a service using the RestTemplate in Spring Boot. The application works fine when i use Postman but from Java Application i get 400 Bad Request.
My Java Sample :
#PostMapping("/service")
private String generateAuthenticationToken() {
HttpHeaders authenticationTokenHeaders = new HttpHeaders();
authenticationTokenHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
JSONObject sfmcBUCredential = new JSONObject();
JSONObject sfmcTokenResponseObject;
sfmcBUCredential.put("grant_type", sfmcConfig.getGrant_type());
sfmcBUCredential.put("client_id", sfmcConfig.getClient_id());
sfmcBUCredential.put("client_secret", sfmcConfig.getClient_secret());
String sfmcBUCredentialString = sfmcBUCredential.toString();
System.out.println("Values before sending to POST Request are :::" + sfmcBUCredentialString);
HttpEntity<String> getTokenEntity = new HttpEntity<>(sfmcBUCredentialString, authenticationTokenHeaders);
System.out.println("Values after sending to POST Request are :::" + getTokenEntity.toString());
System.out.println("URL is :::" + GET_SFMC_ENDPOINT_URL);
//String tokenResponse = restTemplate.postForObject(GET_SFMC_ENDPOINT_URL, getTokenEntity, String.class);
ResponseEntity<String> tokenResponse = restTemplate.exchange(GET_SFMC_ENDPOINT_URL, HttpMethod.POST, getTokenEntity, String.class);
sfmcTokenResponseObject = new JSONObject(tokenResponse.getBody());
System.out.println("tokenResponse::::::::" + sfmcTokenResponseObject.getString("access_token").toString());
return sfmcTokenResponseObject.getString("access_token");
}
Logs :
Values before sending to POST Request are :::{"grant_type":"client_credentials","client_secret":"c1ae4b4a-498e-46a0-a02e-cd2378cb8db6","client_id":"Y43iLAhr4e0SoJ9KkV4vLKnGhNmS1Y3c"}
Values after sending to POST Request are :::<{"grant_type":"client_credentials","client_secret":"c1ae4b4a-498e-46a0-a02e-cd2378cb8db6","client_id":"Y43iLAhr4e0SoJ9KkV4vLKnGhNmS1Y3c"},[Content-Type:"application/x-www-form-urlencoded"]>
URL is :::https://keycloak.lab.hci.aetna.com/auth/realms/master/protocol/openid-connect/token
Try something like this:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", sfmcConfig.getGrant_type());
map.add("client_id", sfmcConfig.getClient_id());
map.add("client_secret", sfmcConfig.getClient_secret());
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
ResponseEntity<LabelCreationResponse> response =
restTemplate.exchange("url",
HttpMethod.POST,
entity,
String.class);
I use RestTemaplteBuilder for send POST request to Telegram Bot API.
There was a problem creating the request to upload the audio file.
According to the documentation - https://core.telegram.org/bots/api#sending-files you need to send a request of type multipart/form-data.
Error: 413 Request Entity Too Large
MultiValueMap<String, Object> request= new LinkedMultiValueMap<String, Object>();
try {
parts.set("chat_id", "id");
parts.set("audio", (Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("name.mp3").toURI()))));
} catch (Exception e) {
e.printStackTrace();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(request, headers);
ResponseEntity<String> responseEntity = restTemplateBuilder.build().postForEntity(requestFormatter(URL_BOT_PREFIX, method), requestEntity, String.class);
I want to turn this postman client with multipart/form-data header request to a spring template client.
Right now, I have a basic rest controller which works well.
#RestController
#RequestMapping("/api")
public class MainConroller {
private static final Logger log = LoggerFactory.getLogger(MainConroller.class);
#Autowired
private MainService mainService;
public MainConroller(MainService mainService) {
this.mainService = mainService;
}
#PostMapping("/mails/send")
public void send(
#RequestParam("usertoken") String usertoken,
#RequestParam("sendTo") String sendTo,
#RequestParam("subject") String subject,
#RequestParam("content") String content,
#RequestParam(required = false, name = "files") List<MultipartFile> multipartFiles) {
log.debug("{}, {}, {}, {}", usertoken, sendTo, subject, content);
mainService.processMessage(usertoken, sendTo, subject, content, multipartFiles);
}
}
I need to, however, create a rest client so I used a rest template, it right now looks like this:
ArrayList<HttpMessageConverter<?>> converters = new ArrayList<>(
Arrays.asList(new MappingJackson2HttpMessageConverter(), new ResourceHttpMessageConverter(), new FormHttpMessageConverter()));
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(converters);
}
File file = new File("*********");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> fileValueMap = new LinkedMultiValueMap<>();
fileValueMap.add(file.getName(), file);
fileValueMap.add(file.getName(), file);
fileValueMap.add(file.getName(), file);
HttpEntity<MultiValueMap<String, Object>> filesPart = new HttpEntity<>(fileValueMap, httpHeaders);
// String key values part
MultiValueMap<String, String> stringPart = new LinkedMultiValueMap<>();
stringPart.add("usertoken", "test");
stringPart.add("sendTo", "test");
stringPart.add("subject", "test");
stringPart.add("content", "test");
HttpEntity<MultiValueMap<String, String>> objectPart = new HttpEntity<>(stringPart, httpHeaders);
MultiValueMap<String, Object> multiPartRequest = new LinkedMultiValueMap<>();
multiPartRequest.add("ObjectPart", objectPart);
multiPartRequest.add("FilesPart", filesPart);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiPartRequest, httpHeaders);
String serverUrl = "****";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
The problem is when I try to send the post request, It throws
Exception in thread "main" org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [multipart/form-data]
Update
The solution on the client side is very simple, you can just send String values in the object values, which are going to be automatically casted to Strings via generics.
Also, the files cannot be send just as files but you have to create FileSystemResource instead, here is the complete code of the client side:
#Service
public class RestTemplatePost {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public void prepareMessage() throws Exception {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("usertoken", "test");
form.add("sendTo", "test");
form.add("subject", "test");
form.add("content", "test");
form.add("files", getTestFile());
form.add("files", getTestFile());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, httpHeaders);
String serverUrl = "******";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
}
public static Resource getTestFile() throws IOException {
Path testFile = Paths.get("C****");
System.out.println("Creating and Uploading Test File: " + testFile);
Files.write(testFile, "Hello World !!, This is a test file.".getBytes());
return new FileSystemResource(testFile.toFile());
}
}
You are making things too complex. You should use a single map to hold the form values not a map of maps. Next to that Spring Boot already provides a RestTemplate so you don't need to configure your own again.
File file = new File("*********");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("files", file);
form.add("files", file);
form.add("files", file);
form.add("usertoken", "test");
form.add("sendTo", "test");
form.add("subject", "test");
form.add("content", "test");
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, httpHeaders);
String serverUrl = "****";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
The RestTemplate (or actually the FormHttpMessageConverter) will transform it into a correct request.
The default RestTemplate constructor does not include any message converters, you need to add it. For example, you can do it like:
HttpEntity<MultiValueMap<String, Object>> requestEntity = new
HttpEntity<MultiValueMap<String, Object>>(parts, requestHeaders);
RestTemplate restTemplate = getRestTemplate();
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
return restTemplate.postForObject(apiURI, requestEntity, String.class);
I am using Spring's RestTemplate to send a POST request to my RestController with request parameters and a request header.
It fails with this error message: POST request for "[myurl]" resulted in 404 (null); invoking error handler.
Note that "[myurl]" is "http://localhost:8080/test"
This is my code:
RestTemplate rest = new RestTemplate();
MultiValueMap<String, Integer> map = new LinkedMultiValueMap<String, Integer>();
map.add("num1", 1);//request parameters
map.add("num2", 2);
HttpHeaders headers = new HttpHeaders();//request header
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<MultiValueMap<String, Integer>> request = new HttpEntity<MultiValueMap<String, Integer>>(map, headers);
Object obj = rest.postForObject("[myurl]", request, Object.class);
logger.log("Returned object: " + obj.toString());
Maybe try doing something like (if you can get away with MultiValueMap):
RestTemplate rest = new RestTemplate();
Map<String, Integer> map = new HashMap<>();
map.put("num1", 1);//request parameters
map.put("num2", 2);
Object obj = rest.postForObject("[myurl]", map, Object.class);
logger.log("Returned object: " + obj.toString());
I am triggering a GET request and getting the JSON data successfully via Spring RestTemplate. I also want to get the Response Header information but I am not sure how to get it.
private String getAPIKeySpring() {
RestTemplate restTemplate = new RestTemplate();
String url = baseURL+"/users/apikey";
Map<String, String> vars = new HashMap<String, String>();
vars.put("X-Auth-User", apiUser);
JsonVO jsonVO = restTemplate.getForObject(url, JsonVO.class, vars);
System.out.println(jsonVO);
return null;
}
ResponseEntity<JsonVO> responseEntity = restTemplate.getForEntity(url, JsonVO.class, vars);
JsonVO jsonVO = responseEntity.getBody();
HttpHeaders headers = responseEntity.getHeaders(); //<-- your headers