Java - 422 Unprocessable Entity using RestTemplate - java

I have two services, Am trying to send a GET request from Service A, To make Service B send a Post request to Redmine Server.
Am getting 422 Unprocessable Entity: "{"errors":["Name cannot be blank","Identifier cannot be blank"]}"
And here is what I have already tried :
String url = "http://localhost:3001/projects.json"; //Redmine local server
RestTemplate restTemplate = new RestTemplate();
JSONObject object = new JSONObject(); //Json object that will need to be sent to redmine
object.put("name", "dummyName"); // Should look like this
object.put("identifier", "dummyId"); // {"project":{"identifier":"dummyId","name":"dummyName"}}
JSONObject body = new JSONObject();
body.put("project", object);
String plainCreds = "user:bitnami1"; // default basic auth encoding
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
RequestEntity<JSONObject> requestEntity = RequestEntity
.post(new URI(url))
.accept(MediaType.APPLICATION_JSON)
.headers(headers)
.body(body);
ResponseEntity<String> r = restTemplate.exchange(requestEntity, String.class);
This way am getting the same error, 422 Unprocessable Entity: "{"errors":["Name cannot be blank", "Identifier cannot be blank"]}"
And when I try to log.info the Request Entity to check it look ok
<POST http://localhost:3001/projects.json,{"project":{"identifier":"dummyId","name":"dummyName"}},[Accept:"application/json", Authorization:"Basic dXNlcjpiaXRuYW1pMQ==", Content-Type:"application/json"]>
Then I've Tried with entity , As the following
String url = "http://localhost:3001/projects.json"; //Redmine local server
RestTemplate restTemplate = new RestTemplate();
JSONObject object = new JSONObject(); //Json object that will need to be sent to redmine
object.put("name", "dummyName"); // Should look like this
object.put("identifier", "dummyId"); // {"project":{"identifier":"dummyId","name":"dummyName"}}
JSONObject body = new JSONObject();
body.put("project", object);
String plainCreds = "user:bitnami1"; // default basic auth encoding
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
HttpEntity<Object> entity = new HttpEntity<Object>(body, headers);
ResponseEntity<String> result = restTemplate.exchange("http://localhost:3001/projects.json",
HttpMethod.POST,
entity,
String.class);
The same result as earlier, When I log.info for entity-body I get the following
<{"project":{"identifier":"dummyId","name":"dummyName"}},[Authorization:"Basic dXNlcjpiaXRuYW1pMQ==", Content-Type:"application/json"]>
Tried To use NetCat to capture what is being sent, In both ways am not getting any body with restTemplate.exchange.
While debugging, It seems that the error came from RestTemplate.doExecute And I cant get why.
----Edit----
Am trying to connect to Redmine API to create new Project, More info can be found here And this is the curl command that successfully create new project
curl --location --request POST 'localhost:3001/projects.json' \
--header 'Authorization: Basic dXNlcjpiaXRuYW1pMQ==' \
--header 'Content-Type: application/json' \
--data-raw '{"project":{"identifier":"dummyId","name":"dummyName"}}'
What I am trying to do, Is to send a request From service A to my Service B so this request will be forwarded to redmine server.
For simplicity, I hard-coded the information in the code above (service B) just to make sure I can map this curl request, But it's not working.
Is there any suggested solution for this situation? Maybe an alternative approach ? Any suggestion would help.

Since your method would accept an object node as an input so you can do something like this:
String url = "http://localhost:3001/projects.json";
RestTemplate restTemplate = new RestTemplate();
Then you can set an HttpEntity like this:
HttpEntity<ObjectNode> entity = new HttpEntity<>(node, headers);
Then call exchange:
ResponseEntity<String> result = restTemplate.exchange("http://localhost:3001/projects.json",
HttpMethod.POST,
entity,
String.class);
I guess this will make your life easier.

Related

I'm getting error "org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request"

I'm getting this error "org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request" while trying to internally call POST API from another GET API in spring boot. following is the code. also I'm getting multipart file as input in the get api and wants to send that file to this internal post api
Path tempFile = Files.createTempFile(null, null);
Files.write(tempFile, newFile.getBytes());
File fileToSend = tempFile.toFile();
FileSystemResource fr = new FileSystemResource(fileToSend);
String baseUrl = "someURL which is correct";
URI uri = new URI(baseUrl);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
//headers.set("Content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
headers.set("Ocp-Apim-Subscription-Key","{key which i dont want to display}");
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("newFile", fr);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(uri, requestEntity, String.class);
return response;
Pass baseUrl string instead of uri in restTemplate.postForEntity method and try

How to do in Resttemplate Spring

curl -u "uname:password" -H "X-Requested-With: Curl" -X "POST" "https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/" > was_finding.txt
How to do the same thing in Spring rest template,
curl -u "uname:password" -H "X-Requested-With: Curl" -X "POST" "https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/" > was_finding.txt
Well, I'm not sure why you have the same request two times. Anyhow, you need to initiate a rest client, that you can reuse, and then use it is as a simple http client for any calls:
// Do once
HttpClient client = HttpClients.createDefault();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(factory));
// Do anytime
byte[] plainCredsBytes = "uname:password".getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
ResponseEntity<String> response = restTemplate.postForEntity(
"https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/",
new HttpEntity(headers), String.class);
if (response.getStatusCode() == HttpStatus.OK) {
Files.writeString(Paths.get("was_finding.txt"), response.getBody());
} else {
// Handle status code, etc.
}
If you need to set up SSL then you need to create a SSLContextBuilder before you build your client, thats it.

Retrieve a cookie using Spring RestTemplate

I need to get a cookie from a server using Spring RestTemplate. Do you guys know how I can perform this?
Thank you for your help!
final String url = "http://codeflex.co:8080/rest/Management/login";
RestTemplate template = new RestTemplate();
Credentials cred = new Credentials();
cred.setUserName("admin#codeflex.co");
cred.setPassword("godmode");
HttpEntity<Credentials> request = new HttpEntity<>(cred);
HttpEntity<String> response = template.exchange(url, HttpMethod.POST, request, String.class);
HttpHeaders headers = response.getHeaders();
String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);
code from the example
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + session.getValue());
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = restTemplate.exchange(
"https://jira.example.com/sr/jira.issueviews:searchrequest-xml/18107/SearchRequest-18107.xml?tempMax=1000",
HttpMethod.GET,
requestEntity,
Rss.class);
Rss rss = rssResponse.getBody();
from http://springinpractice.com/2012/04/08/sending-cookies-with-resttemplate

Translate authorized curl -u post request with JSON data to RestTemplate equivalent

I am using github api to create repositories using curl command as shown below and it works fine.
curl -i -u "username:password" -d '{ "name": "TestSystem", "auto_init": true, "private": true, "gitignore_template": "nanoc" }' https://github.host.com/api/v3/orgs/Tester/repos
Now I need to execute the same above url through HttpClient and I am using RestTemplate in my project.
I have worked with RestTemplate before and I know how to execute simple url but not sure how to post the above JSON data to my url using RestTemplate -
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Create a multimap to hold the named parameters
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
parameters.add("username", username);
parameters.add("password", password);
// Create the http entity for the request
HttpEntity<MultiValueMap<String, String>> entity =
new HttpEntity<MultiValueMap<String, String>>(parameters, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
Can anyone provide an example how would I execute the above URL by posting JSON to it?
I have not had the time to test the code, but I believe this should do the trick. When we are using curl -u, to pass the credentials, it has to be encoded and passed along with the Authorization header, as noted here http://curl.haxx.se/docs/manpage.html#--basic. The json data, is simply passed as a HttpEntity.
String encoding = Base64Encoder.encode("username:password");
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + encoding);
headers.setContentType(MediaType.APPLICATION_JSON); // optional
String data = "{ \"name\": \"TestSystem\", \"auto_init\": true, \"private\": true, \"gitignore_template\": \"nanoc\" }";
String url = "https://github.host.com/api/v3/orgs/Tester/repos";
HttpEntity<String> entity = new HttpEntity<String>(data, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity , String.class);

Making authenticated POST requests with Spring RestTemplate for Android

I have a RESTful API I'm trying to connect with via Android and RestTemplate. All requests to the API are authenticated with HTTP Authentication, through setting the headers of the HttpEntity and then using RestTemplate's exchange() method.
All GET requests work great this way, but I cannot figure out how to accomplish authenticated POST requests. postForObject and postForEntity handle POSTs, but have no easy way to set the Authentication headers.
So for GETs, this works great:
HttpAuthentication httpAuthentication = new HttpBasicAuthentication("username", "password");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(httpAuthentication);
HttpEntity<?> httpEntity = new HttpEntity<Object>(requestHeaders);
MyModel[] models = restTemplate.exchange("/api/url", HttpMethod.GET, httpEntity, MyModel[].class);
But POSTs apparently don't work with exchange() as it never sends the customized headers and I don't see how to set the request body using exchange().
What is the easiest way to make authenticated POST requests from RestTemplate?
Ok found the answer. exchange() is the best way. Oddly the HttpEntity class doesn't have a setBody() method (it has getBody()), but it is still possible to set the request body, via the constructor.
// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("field", "value");
// Note the body object as first parameter!
HttpEntity<?> httpEntity = new HttpEntity<Object>(body, requestHeaders);
ResponseEntity<MyModel> response = restTemplate.exchange("/api/url", HttpMethod.POST, httpEntity, MyModel.class);
Slightly different approach:
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("HeaderName", "value");
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(objectToPass, headers);
restTemplate.postForObject(url, request, ClassWhateverYourControllerReturns.class);
I was recently dealing with an issue when I was trying to get past authentication while making a REST call from Java, and while the answers in this thread (and other threads) helped, there was still a bit of trial and error involved in getting it working.
What worked for me was encoding credentials in Base64 and adding them as Basic Authorization headers. I then added them as an HttpEntity to restTemplate.postForEntity, which gave me the response I needed.
Here's the class I wrote for this in full (extending RestTemplate):
public class AuthorizedRestTemplate extends RestTemplate{
private String username;
private String password;
public AuthorizedRestTemplate(String username, String password){
this.username = username;
this.password = password;
}
public String getForObject(String url, Object... urlVariables){
return authorizedRestCall(this, url, urlVariables);
}
private String authorizedRestCall(RestTemplate restTemplate,
String url, Object... urlVariables){
HttpEntity<String> request = getRequest();
ResponseEntity<String> entity = restTemplate.postForEntity(url,
request, String.class, urlVariables);
return entity.getBody();
}
private HttpEntity<String> getRequest(){
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + getBase64Credentials());
return new HttpEntity<String>(headers);
}
private String getBase64Credentials(){
String plainCreds = username + ":" + password;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
return new String(base64CredsBytes);
}
}
Very useful
I had a slightly different scenario where I the request xml was itself the body of the POST and not a param. For that the following code can be used - Posting as an answer just in case anyone else having similar issue will benefit.
final HttpHeaders headers = new HttpHeaders();
headers.add("header1", "9998");
headers.add("username", "xxxxx");
headers.add("password", "xxxxx");
headers.add("header2", "yyyyyy");
headers.add("header3", "zzzzz");
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
final HttpEntity<MyXmlbeansRequestDocument> httpEntity = new HttpEntity<MyXmlbeansRequestDocument>(
MyXmlbeansRequestDocument.Factory.parse(request), headers);
final ResponseEntity<MyXmlbeansResponseDocument> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity,MyXmlbeansResponseDocument.class);
log.info(responseEntity.getBody());

Categories