How to set JSON payload on AmazoneWebServiceRequest - java

I am using AmazonHttpClient & AmazonWebServiceRequest to make http requests to API gateway from android app. The requestBody is a JSON String and DefaultRequest only seem to accept InputStream as content.
final AmazonWebServiceRequest awsRequest = new AmazonWebServiceRequest() {};
final Request request = new DefaultRequest(awsRequest, UtilConstants.API_GATEWAY_SERVICE_NAME);
request.setEndpoint(uri);
request.setHttpMethod(requestType);
request.addHeader(HttpHeader.CONTENT_TYPE, "application/json");
final InputStream stream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
request.setContent(stream);
When I make the request I get following exception
Caused by: com.amazonaws.AmazonClientException: Unable to execute HTTP request: expected 0 bytes but received 38

adding HttpHeader.CONTENT_LENGTH header solved the issue.

Related

Getting java.io.IOException: Server returned HTTP response code: 400 for URL: when using a url which return 400 status code

I am trying to perform a get request using Groovy using the below code:
String url = "url of endpoint"
def responseXml = new XmlSlurper().parse(url)
If the endpoint returns status as 200 then everything works good but there is one case where we have to validate the error response like below and status returned is 400:
<errors>
<error>One of the following parameters is required: xyz, abc.</error>
<error>One of the following parameters is required: xyz, mno.</error>
</errors>
In this case parse method throws :
java.io.IOException: Server returned HTTP response code: 400 for URL: "actual endpoint throwing error"
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1900)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:646)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:150)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:831)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:796)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:142)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:644)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:205)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:271)
Can anyone pls suggest how to handle if server give error message by throwing 400 status code?
In the question since we are getting 400 status code for GET request. So in built XmlSlurper().parse(URI) method does not work as it throw io.Exception.
Groovy also support HTTP methods for api request and response and the below worked for me:
def getReponseBody(endpoint) {
URL url = new URL(endpoint)
HttpURLConnection get = (HttpURLConnection)url.openConnection()
get.setRequestMethod("GET")
def getRC = get.getResponseCode()
BufferedReader br = new BufferedReader(new InputStreamReader(get.getErrorStream()))
StringBuffer xmlObject = new StringBuffer()
def eachLine
while((eachLine = br.readLine()) !=null){
xmlObject.append(eachLine)
}
get.disconnect()
return new XmlSlurper().parseText(xmlObject.toString())
}
Getting the response text from the HttpURLConnection class rather than implicitly through XmlSlurper allows you much more flexibility in handling unsuccessful responses. Try something like this:
def connection = new URL('https://your.url/goes.here').openConnection()
def content = { ->
try {
connection.content as String
} catch (e) {
connection.responseMessage
}
}()
if (content) {
def responseXml = new XmlSlurper().parseText(content)
doStuffWithResponseXml(responseXml)
}
Even better would be to use an actual full-featured HTTP client, like the Spring Framework's HttpClient or RestTemplate classes.
You should check the return code and than obtain the error stream from http request instance in case of an error. The problem itself has nothing to do with JsonSlurper, as no instance of "input stream" is returned from http request instance if service returns not successfull return codes (400, 401, 500 etc.) POST example can be seen below:
http= new URL("yourUrl").openConnection() as HttpURLConnection
http.setRequestMethod('POST')
http.setDoOutput(true)
http.setRequestProperty("Content-Type", 'application/json')
http.setRequestProperty("Accept", 'application/json')
http.setRequestProperty("Authorization", "Bearer $yourTokenVariable")
http.outputStream.write(data.getBytes("UTF-8"))
http.connect()
if(http.getResponseCode() != 200 && http.getResponseCode() != 201){
throw new InvalidInputException("There was an error: " + http.getErrorStream().getText("UTF-8"))
} else {
//You can take input stream here
}

Stream ending unexpectedly when doing a multipart form-data request

So we have a server app written in java and it has a rest service to which you can upload files in the form of a multipart request. This is the signature of the method
#POST
#Transactional(TxType.REQUIRED)
#Path("/{id}")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public ContentInfo uploadToInstanceFromMultipart(UploadRequest uploadRequest, #PathParam(JsonKeys.ID) String id) {
As you can see thre is nothing special about it, just a post service. However on the other side we are writing an ms office plugin (VSTO) that sends a file to that service using RestSharp.
void Application_DocumentBeforeSave(Word.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
var client = new RestClient("...");
client.Authenticator = new HttpBasicAuthenticator(...);
var request = new RestRequest("api/content/{id}", Method.POST);
var name = Doc.Name;
var contentId = getContentId(name);
var fileName = getName(name);
request.AddUrlSegment("id", contentId);
request.AddFile(fileN, Doc.Path + "\\" + Doc.Name, "application/msword");
IRestResponse response = client.Execute(request);
var content = response.Content;
MessageBox.Show(content);
And i don't see anything special in here too but when saving the file (thus sending it to the server), the server responds with the following exception
(default task-33) Generic exception: javax.ws.rs.WebApplicationException: Processing of multipart/form-data request failed. Stream ended unexpectedly
And boils down to
Caused by: org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:1005)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:903)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at org.apache.commons.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:134)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:100)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:347)
... 70 more
Any ideas what is going on with the request?

Dropwizard Jersey client Multipart http request

Dropwizard (Version 0.8.2) uses Jersey internally to provide HTTP client. I am using this client to send a Multipart POST request to an external Rest Endpoint to a SMS Service. Code is given below but it doesn't seems to be working because i am not receiving any message through this method also it does not throw any error.
URI for the first sample is http://enterprise.com/GatewayAPI/rest?userid=%s&password=%s&method=xlsUpload&filetype=zip&msg_type=TEXT&auth_scheme=PLAIN&v=1.1
FileDataBodyPart fileDataBodyPart = new FileDataBodyPart(fileName, file,
MediaType.APPLICATION_OCTET_STREAM_TYPE);
FormDataMultiPart multiPart = new FormDataMultiPart();
multiPart.field("fileName", fileName).bodyPart(fileDataBodyPart);
Entity<FormDataMultiPart> entity =
Entity.entity(multiPart, multiPart.getMediaType());// MediaType.MULTIPART_FORM_DATA_TYPE)
Client tenacityClient = TenacityJerseyClientBuilder
.builder(AppDependencyKeys.BULK_SMS)
.usingTimeoutPadding(Duration.milliseconds(500)).build(client)
.register(MultiPartFeature.class);
Invocation invocation = getResourceBuilder(tenacityClient, uri).buildPost(entity);
Future<Response> futureResponse = invocation.submit();
long start = System.currentTimeMillis();
futureResponse.get();
But the same works with below method when i use Apache Commons Httpclient. working code for the same is given below.
HttpClient client = new HttpClient();
PostMethod method = new
PostMethod("http://enterprise.com/GatewayAPI/rest");
Part[] parts = {
new StringPart("method", "xlsUpload"),
new StringPart("userid", "*******"),
new StringPart("password", "*******"),
new StringPart("filetype", "zip"),
new StringPart("v", "1.1"),
new StringPart("auth_scheme", "PLAIN"),
new FilePart(file.getName(), file)
};
method.setRequestEntity(new MultipartRequestEntity(parts, method.getParams()));
int statusCode = client.executeMethod(method);
log.info("Status code: {}", statusCode);
But i want to use the first way as that suits my infrastructure better.
I think you should set up properly media type for entity. Currently, you created new FormDataMultiPart but, you did not set and media type and it uses "text/plain" y default.
So, you should set up MediaType.APPLICATION_OCTET_STREAM_TYPE to your FormDataMultiPart as media type.

How to receive application/pdf response from a server using RestTemplate

I am trying capture the response of an HTTP request made by my java client code. The response has a content-type of application/pdf. In the logs I can see that the server sent a response in
Object result = getRestTemplate().postForObject(urlString, formDataHttpEntity, returnClassObject, parametersMapStringString);
and I get the following JUnit error:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type
[java.lang.Object] and content type [application/pdf]
What do I need to do to get past this? My ultimate goal is to take this in a byte[] and push it in a DB table field of blob type
Note: I get the following response header from the server
HTTP/1.1 200 OK Cache-Control: max-age=0,must-revalidate
Content-Disposition: attachment; filename="Executive Summary.PDF"
Content-Type: application/pdf
Thanks Thomas it worked.
I added ByteArrayHttpMessageConverter to the RestTemplate and it worked.
Code I added:
ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
List<MediaType> supportedApplicationTypes = new ArrayList<>();
MediaType pdfApplication = new MediaType("application","pdf");
supportedApplicationTypes.add(pdfApplication);
byteArrayHttpMessageConverter.setSupportedMediaTypes(supportedApplicationTypes);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(byteArrayHttpMessageConverter);
restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
Object result = getRestTemplate().getForObject(url, returnClass, parameters);
byte[] resultByteArr = (byte[])result;
API I calling to get PDF is returning InputStreamResource.
To get the response, I used it this way and I was able to get a successful byte array of pdf.
public byte[] callApiToGetPDF(Object reqData) {
String urlForEndPoint= baseUrl + "/" + "";
HttpEntity<Object> entity = new HttpEntity<>(reqData, buildHeaders());
return restTemplate.postForEntity(urlForEndPoint, entity, byte[].class).getBody();
}

Send XMLRPC Request using Java

I am trying to send an XMLRPC Request via Java and is unsuccessful. Here's the structure of XMLRPC Request that I need to send with method name create.account:
<createaccount>
<functioncode>bank_account</functioncode> <cardnumber>55553263654898</cardnumber>
<transaction_id>12345678</transaction_id>
<transactiondatetime>2012-01-08 14:12:22</transactiondatetime>
</createaccount>
As per client, I should be expecting the following XMLRPC Response:
<createaccount>
<code>200</code>
<message>SUCCESS</message>
<functioncode>bank_account</functioncode>
<cardnumber>55553263654898</cardnumber>
<transaction_id>12345678</transaction_id>
<transactiondatetime>2012-01-08 14:12:22</transactiondatetime>
</createaccount>
I have made the following snippet in java but I'm getting an error: 'Failed to create input stream: Server returned HTTP response code: 500 for URL'
Here's the snippet:
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL(server_url));
XmlRpcClient client = new XmlRpcClient();
config.setBasicUserName(pUser);
config.setBasicPassword(pPassword);
client.setConfig(config);
Map m = new HashMap();
m.put("functioncode", "bank_account");
m.put("cardnumber", "55553263654898");
m.put("transaction_id", "12345678");
m.put("transactiondatetime", "2012-01-08 14:12:22");
Object[] params = new Object[]{m};
String result = (String)client.execute("bank.account", params);
System.out.println("Results:" + result);
How I can do this?
I would recommend using XML-RPC library, for example Redston XML-RPC. More info and tutorial can be found here.

Categories

Resources