Invalid HTTP method: PATCH - java

After trying other solutions from HttpURLConnection Invalid HTTP method: PATCH
I am getting Invalid HTTP Method: PATCH Exception with JAVA 7.
Updating JAVA is not in option so i have to stick to the workarounds.
I am using Invocation to invoke the request like this
Invocation invoke = reqBuilder.build(getHTTPVerb(), Entity.entity(requestJSON, MediaType.APPLICATION_JSON));
getWebTarget().request(MediaType.APPLICATION_JSON).header("Authorization", getAuthorization()).accept(MediaType.APPLICATION_JSON);
getHTTPVerb() returns String "POST" or "PATCH".
With PATCH method I am having problem.
In the mentioned question, i have not tried one solution with:
conn.setRequestProperty("X-HTTP-Method-Override", "PATCH");
conn.setRequestMethod("POST");
conn is HttpURLConnection instance.
But I am not sure how I can get HttpURLConnection from Invocation class or any property.
Any pointers or help would be highly appreciated.

An example of PATCH method with apache http client:
try {
//This is just to avoid ssl hostname verification and to trust all, you can use simple Http client also
CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
HttpPatch request = new HttpPatch(REST_SERVICE_URL);
StringEntity params = new StringEntity(JSON.toJSONString(payload), ContentType.APPLICATION_JSON);
request.setEntity(params);
request.addHeader(org.apache.http.HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
HttpResponse response = httpClient.execute(request);
String statusCode = response.getStatusLine().getStatusCode();
} catch (Exception ex) {
// handle exception here
}
Equivalent example with RestTemplate:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
final HttpEntity<String> entity = new HttpEntity<String>(JSON.toJSONString(payload), headers);
RestTemplate restTemplate = new RestTemplate();
try {
ResponseEntity<String> response = restTemplate.exchange(REST_SERVICE_URL, HttpMethod.PATCH, entity, String.class);
String statusCode = response.getStatusCode();
} catch (HttpClientErrorException e) {
// handle exception here
}

Related

Send JSON body in HTTP GET request in java/spring boot

I need to send a GET request with a json body in java/spring boot. I'm aware of the advice against it, however I have to do it this was for a couple of reasons:
1. The 3rd party API I'm using only allows GET requests, so POST is not an option.
2. I need to pass an extremely large parameter in the body (a comma separated list of about 8-10k characters) so tacking query params onto the url is not an option either.
I've tried a few different things:
apache HttpClient from here: Send content body with HTTP GET Request in Java. This gave some error straight from the API itself about a bad key.
URIComponentsBuilder from here: Spring RestTemplate GET with parameters. This just tacked the params onto the url, which as I explained before is not an option.
restTemplate.exchange. This seemed the most straightforward, but the object wouldn't pass: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#exchange-java.lang.String-org.springframework.http.HttpMethod-org.springframework.http.HttpEntity-java.lang.Class-java.util.Map-
as well as probably another thing or two that I've forgotten about.
Here is what I'm talking about in Postman. I need to be able to pass both of the parameters given here. It works fine if run through Postman, but I can't figure it out in Java/Spring Boot.
Here is a code snippet from the restTemplate.exchange attempt:
public String makeMMSICall(String uri, List<String> MMSIBatchList, HashMap<String, String> headersList) {
ResponseEntity<String> result = null;
try {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
for (String key : headersList.keySet()) {
headers.add(key, headersList.get(key));
}
Map<String, String> params = new HashMap<String, String>();
params.put("mmsi", String.join(",", MMSIBatchList));
params.put("limit", mmsiBatchSize);
HttpEntity<?> entity = new HttpEntity<>(headers);
result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class, params);
System.out.println(result.getBody());
} catch (RestClientException e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
} catch (Exception e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
}
return result.getBody();
}
Thanks for helping!
You can try java.net.HttpUrlConnection, it works for me but indeed I normally use a POST
HttpURLConnection connection = null;
BufferedReader reader = null;
String payload = "body";
try {
URL url = new URL("url endpoint");
if (url.getProtocol().equalsIgnoreCase("https")) {
connection = (HttpsURLConnection) url.openConnection();
} else {
connection = (HttpURLConnection) url.openConnection();
}
// Set connection properties
connection.setRequestMethod(method); // get or post
connection.setReadTimeout(3 * 1000);
connection.setDoOutput(true);
connection.setUseCaches(false);
if (payload != null) {
OutputStream os = connection.getOutputStream();
os.write(payload.getBytes(StandardCharsets.UTF_8));
os.flush();
os.close();
}
int responseCode = connection.getResponseCode();
}
There's no way of implementing it via RestTemplate, even with .exchange method. It'll simply not send the request body for GET calls even if we pass the entity within the function parameters.(Tested via interceptor logs)
You can use the Apache client to solve this issue/request (whatever you'd like to call it). The code you need is something along following lines.
private static class HttpGetWithBody extends HttpEntityEnclosingRequestBase {
JSONObject requestBody;
public HttpGetWithBody(URI uri, JSONObject requestBody) throws UnsupportedEncodingException {
this.setURI(uri);
StringEntity stringEntity = new StringEntity(requestBody.toString());
super.setEntity(stringEntity);
this.requestBody = requestBody;
}
#Override
public String getMethod() {
return "GET";
}
}
private JSONObject executeGetRequestWithBody(String host, Object entity) throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
JSONObject requestBody = new JSONObject(entity);
URL url = new URL(host);
HttpRequest request = new HttpGetWithBody(url.toURI(), requestBody);
request.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
HttpResponse response;
if(url.getPort() != 0) response = httpClient.execute(new HttpHost(url.getHost(), url.getPort()), request);
else response = httpClient.execute(new HttpHost(url.getHost()), request);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
JSONObject res = new JSONObject(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
httpClient.close();
return res;
}
}catch (Exception e){
log.error("Error occurred in executeGetRequestWithBody. Error: ", e.getStackTrace());
}
httpClient.close();
return null;
}
If you inspect even Apache client library doesn't support passing the body natively(checked via code implementation of HttpGet method), since contextually request body for a GET request is not a good and obvious practice.
Try creating a new custom RequestFactory.
Similar to
get request with body

Calling APIGateway endpoint with HttpGet from Java

I'm trying to call an APIGateway endpoint using a HttpGet in Java. Here's what my code looks like:
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
String HOST = "https://<resourceId>.execute-api.us-west-2.amazonaws.com/beta/update";
/* Prepare get request */
HttpGet httpGet = new HttpGet(HOST);
/* Add headers to get request */
httpGet.addHeader("Content-Type", "application/json");
httpGet.addHeader("host", HOST);
TreeMap<String, String> awsHeaders = new TreeMap<String, String>();
awsHeaders.put("host", HOST);
AWSV4Auth awsAuth = new AWSV4Auth.Builder("key","value")
.regionName("us-west-2")
.serviceName("execute-api") // es - elastic search. use your service name
.httpMethodName("GET") //GET, PUT, POST, DELETE, etc...
.debug()
.awsHeaders(awsHeaders)
.build();
Map<String, String> headers = awsAuth.getHeaders();
for (Map.Entry<String, String> entrySet : headers.entrySet()) {
httpGet.addHeader(entrySet.getKey(), entrySet.getValue());
}
System.out.println("Actual http headers");
List<Header> getHeaders = Arrays.asList(httpGet.getAllHeaders());
for (Header header: getHeaders) {
System.out.println(header.getName() + " : " + header.getValue());
}
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
String jsonResponse = EntityUtils.toString(entity, "UTF-8");
System.out.println("jsonResponse" + jsonResponse);
} catch (Exception e) {
System.out.println("Error calling HttpClient");
e.printStackTrace();
}
}
My APIGateway stage name is beta and the methodName is update.
I'm using this GitHub class here for signing my request - https://github.com/javaquery/Examples/blob/master/src/com/javaquery/aws/AWSV4Auth.java
I always keep seeing this error - "This request could not be satisfied."
I used postman as a reference to generate the headers and I still cannot figure out what or where am I going wrong.
I a not trying to use the generated SDK from APIGateway because of a specific internal problem. Am I missing any other headers which need to be passed in?

Empty request when sending special characters to API with Java

I'm using Java to send http requests to my API which is created using Laravel (5.4). If I send a request without any special characters it all works like a charm. But if there are any 'special' characters like: é, å, ö and such the request in Laravel is empty:
dd(request()->all()) outputs []
I guess this has to do with some wrong settings while creating the request in Java. I couldn't find a solution.
Here is the code responsible for creating the request.
public class HttpClient {
org.apache.http.client.HttpClient client;
public HttpClient() {
client = HttpClientBuilder.create().build();
}
public void post(String json) {
try {
HttpPost request = buildPostRequest(json);
HttpResponse response = createClient().execute(request);
int code = getStatusCode(response);
if (code != 200) {
throw new Exception("Error (" + code + ") on server.");
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
private org.apache.http.client.HttpClient createClient() {
return HttpClientBuilder.create().build();
}
private HttpPost buildPostRequest(String json) throws Exception {
HttpPost request = new HttpPost("some uri");
request.addHeader("Content-type", "application/json; charset=utf-8");
request.addHeader("Accept", "application/json");
StringEntity params = new StringEntity(json);
params.setContentEncoding("utf-8");
params.setContentType("application/json; charset=utf-8");
request.setEntity(params);
return request;
}
private int getStatusCode(HttpResponse response) {
StatusLine line = response.getStatusLine();
return line.getStatusCode();
}
}
EDIT
Dump of the request before it get's send to the API.
I found a solution to the problem. In the buildPostRequest() method I changed from a StringEntity to a ByteArrayEntity and coverted the string to UTF-8 bytes.
ByteArrayEntity params = new ByteArrayEntity(json.getBytes("UTF-8"));
If I send special characters to the API the request isn't empty anymore.
try this way
HttpPost request = new HttpPost(URLEncoder.encode("url here", "UTF-8"));

Call rest API from java rest API

I have a java rest API hosted on JBoss which call another rest webservice:
#GET
#Path("/testDeployment")
#Produces(MediaType.TEXT_PLAIN)
public String testDeployment() {
URL url = new URL(restURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer "+sessionId);
System.out.println("sessionId>>>> "+sessionId);
System.out.println("restURL>>>> "+restURL);
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
response += output;
}
conn.disconnect();
}
But I am getting error
Server returned HTTP response code: 401 for URL: https://cs5.salesforce.com/services/apexrest/event/search?type=init
13:16:08,738 ERROR [stderr] (default task-26) java.io.IOException: Server returned HTTP response code: 401 for URL: https://cs5.salesforce.com/services/apexrest/event/search?type=init
13:16:08,747 ERROR [stderr] (default task-26) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
The following is the extract from the definition of Http Status Code Definitions, which might help you to solve the problem:
401 Unauthorized
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication"
what ever URL you are hitting is Authorized, so have to use authorization in header then you will get output as
1. if you are using jersey then use syntax as below:-
try{
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8085/getStepsCount");
webResource.setProperty("Content-Type", "application/json;charset=UTF-8");
String authorization = "PASTE_KEY_HERE";
webResource.setProperty("Authorization", authorization);
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("json", js);
String jsonString = webResource.get(String.class);}catch (Exception e){System.out.println (e.getMessage());}
and if you are using Spring Rest Controller then use this one.......
#RequestMapping(value = "/getStepsUsingPostRequest", method = RequestMethod.POST)
public ResponseEntity<Object> getDiscountUsingPost(
#RequestBody MemberStepsDto memberStepsDto) {
try{
final String uri = "http://localhost:8085/getStepsCount";
RestTemplate restTemplate = new RestTemplate();
System.out.println("starting.......");
String json = "{\"memberId\": \""+memberStepsDto.getMemberId()+"\",\"startDate\": \""+memberStepsDto.getStartDate()+"\",\"endDate\": \""+memberStepsDto.getEndDate()+"\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(json,headers);
String answer = restTemplate.postForObject(uri, entity, String.class);
System.out.println("String : " + answer);
}
catch(Exception ex){
ex.printStackTrace();
}
return new ResponseEntity<Object>(new String("Fetched Successfully"),HttpStatus.OK);
}
I did add the Authorization Header :
conn.setRequestProperty("Authorization", "Bearer "+sessionId);
But it looks like the header needed to be formatted, I updated the line to:
conn.setRequestProperty("Authorization", String.format("Bearer %s", sessionId));
And it worked, I guess over the web it needs to be formatted and for a java application the above code works well

Java - Sending a post request with HtmlUnit

Can't really find any help on this but I've been trying to send a post request with HtmlUnit. The code I have is:
final WebClient webClient = new WebClient();
// Instead of requesting the page directly we create a WebRequestSettings object
WebRequest requestSettings = new WebRequest(
new URL("www.URLHERE.com"), HttpMethod.POST);
// Then we set the request parameters
requestSettings.setRequestParameters(new ArrayList());
requestSettings.getRequestParameters().add(new NameValuePair("name", "value"));
// Finally, we can get the page
HtmlPage page = webClient.getPage(requestSettings);
Is there an easier way I could carry out a POST request?
This is how it's done
public void post() throws Exception
{
URL url = new URL("YOURURL");
WebRequest requestSettings = new WebRequest(url, HttpMethod.POST);
requestSettings.setAdditionalHeader("Accept", "*/*");
requestSettings.setAdditionalHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
requestSettings.setAdditionalHeader("Referer", "REFURLHERE");
requestSettings.setAdditionalHeader("Accept-Language", "en-US,en;q=0.8");
requestSettings.setAdditionalHeader("Accept-Encoding", "gzip,deflate,sdch");
requestSettings.setAdditionalHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
requestSettings.setAdditionalHeader("X-Requested-With", "XMLHttpRequest");
requestSettings.setAdditionalHeader("Cache-Control", "no-cache");
requestSettings.setAdditionalHeader("Pragma", "no-cache");
requestSettings.setAdditionalHeader("Origin", "https://YOURHOST");
requestSettings.setRequestBody("REQUESTBODY");
Page redirectPage = webClient.getPage(requestSettings);
}
You can customize it however you want. Add/remove headers, add/remove request body, etc ...
There are n numbers of possible libraries using which you can call rest web services.
1) Apache Http client
2) Retrofit from Square
3) Volley from google
I have used Http Apache client and Retrofit both. Both are awesome.
Here is code example of Apache HTTP client to send Post request
String token = null;
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost(LOGIN_URL);
StringBuilder sb = new StringBuilder();
sb.append("{\"userName\":\"").append(user).append("\",").append("\"password\":\"").append(password).append("\"}");
String content = sb.toString();
StringEntity input = new StringEntity(content);
input.setContentType("application/json");
postRequest.setHeader("Content-Type", "application/json");
postRequest.setHeader("Accept", "application/json");
postRequest.setEntity(input);
HttpResponse response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 201)
{
throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
}
Header[] headers = response.getHeaders("X-Auth-Token");
if (headers != null && headers.length > 0)
{
token = headers[0].getValue();
}
return token;

Categories