nni have a problem calling a web service using jersey client.
I tried successfully as a test with : "http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%2248907%22&format=json"
using this code :
Client client = Client.create();
WebResource webResource = client.resource("http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%2248907%22&format=json");
ClientResponse response = webResource.accept("application/json").get(ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
String json = response.getEntity(String.class);
System.out.println(json);
but i can't do it when i call amazon webservice : http://ws.amazon.com/widgets/q?Operation=GetResults&Keywords=cool&SearchIndex=All&multipageStart=0&InstanceId=0&multipageCount=10&TemplateId=8002&ServiceVersion=20070822&MarketPlace=US
Is it because, I get a json file as response ?
Any help please ?
After experimenting with the Amazon web service with various form HTTP requests. I finally figured out that the problem is because of the User-Agent value sent in the HTTP Header.
For some reason, Amazon Rest Service is not able to handle the presence of period character . in the HTTP Header under User-Agent.
When sending a HTTP request with . as below
GET http://ws.amazon.com/widgets/q?Operation=GetResults&Keywords=cool&SearchIndex=All&multipageStart=0&InstanceId=0&multipageCount=10&TemplateId=8002&ServiceVersion=20070822&MarketPlace=US HTTP/1.1
User-Agent: Java.
Host: ws.amazon.com
Connection: keep-alive
Amazon WS sends a HTTP response without Body content
HTTP/1.1 200 OK
Date: Fri, 27 Sep 2013 19:29:54 GMT
Server: Server
Content-Length: 0
Vary: Accept-Encoding,User-Agent
Cneonction: close
Content-Type: text/plain
If the . is removed from the Content-Type, the response body does contain the detailed Json Content. This most likely looks like an issue on Amazon Rest Service implementation.
You can change the code as follows to see the Json content and get away with the problem
ClientResponse response = webResource.header("User-Agent", "SomeAgentNameWithoutPeriodChar").get(ClientResponse.class);
Related
I was trying to call a backend using webclient, which is "chunked" response. But, it appears StringDecoder failed to decode chunked response. As I can see following line logged
LN="o.s.c.c.StringDecoder" [3d736ae4] Decoded "?�????????�V�RPPPrO-?J-.��+NU�R220P(.MNN-.N+�Q�?+).I,)-�?�%�??)(y$??T*?$�d(��?)���(䦖d�(q�r??���}X???"
However, actual response from backend is plain json with following response header :
Content-Encoding : gzip
Vary : Accept-Encoding, User-Agent
Transfer-Encoding : chunked
Couldn't find any similar post on SO, which could point to handle chunked type response using webclient.
Code snippet of webclient part :
Mono<ResponseEntity<String>> response = client.get().uri(url)
.retrieve();
.onStatus(HttpStatus::isError, t -> Mono.empty())
.toEntity(String.class);
I have GET REST API, which sends some information in response header.
I am writing test case using rest assured framework, issue I am facing is, in response of GET API, I am not getting header string set by the server in rest API response.
I have checked the same API in Rest client and HTTP Resource, there I can see the header information set by server in API response.
But in rest assured Response object, header information set by server is not available.
Rest API code:
#Path("/download")
#GET
#Produces("application/zip")
public Response downloadContractZipFile(#PathParam("contractId") final String contractId) throws CMException{
ContractActionRequest contractActionRequest = new ContractActionRequest();
contractActionRequest.setId(contractId);
DownloadActionResponse downloadActionResponse = (DownloadActionResponse) executeAction(Action.DOWNLOAD, contractActionRequest);
Response res = Response
.ok(downloadActionResponse.getFilestream(), MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition",downloadActionResponse.getContentDisposition())
.header("Expires", "0")
.header("Content-Length", String.valueOf(downloadActionResponse.getContentLength()) )
.build();
return res;
}
Above you can see, API is returning Content-Length in header. But when I am invoking above API using rest assured framework, it does not receive "Content-Length" in header. Assert is getting failed.
Rest assured Test case code:
given().get(propertyURI).then().assertThat().header("Content-Length","7562");
java.lang.AssertionError: Expected header "Content-Length" was not "7562", was "null". Headers are:
X-Powered-By=Servlet/3.0
Cache-Control=no-cache, no-store
Cache-directive=no-cache
Pragma=no-cache
Pragma-Directive=no-cache
Expires=Thu, 01 Jan 1970 00:00:00 GMT
Content-Type=text/html;charset=UTF-8
x-authenticated=false
x-location=https://reena:9453/app/login.jsp?targetApp=OM
Content-Language=en-US
Transfer-Encoding=chunked
I suggest you try Karate instead of REST-Assured as it has much better support for validating response headers.
(disclaimer: am Karate dev)
I am trying to build a batch job to access Office 365 Mail API. Up on checking the documentation (the concept is very clear), I wasn't able to find a code sample written for Java. I've found this but it relies on the java pom file but I would love to use REST API or Graphi API directly if possible.
Can someone point me on how to get started with building a Daemon service to access Office 365 REST API without users login ?
UPDATE
I've the following code to get the token using AADL library
String tenant="....";
String authority = "https://login.windows.net/"+tenant+"/oauth2/authorize";
ExecutorService service=null;
service= Executors.newFixedThreadPool(1);
try{
AuthenticationContext authenticationContext= new AuthenticationContext(authority,false,service);
String certFile="/mycert2.pfx";
InputStream pkcs12Cert= new SharedFileInputStream(certFile);
AsymmetricKeyCredential credential=AsymmetricKeyCredential.create("....",pkcs12Cert,"pass");
Future<AuthenticationResult> future=authenticationContext.acquireToken("https://outlook.office365.com",credential,null);
System.out.println("Token Received"+future.get().getAccessToken());
String token = future.get().getAccessToken();
HttpGet httpGet = new HttpGet("https://graph.microsoft.com/v1.0/users");
httpGet.setHeader("Authorization", "Bearer "+token);
GraphServices graphServices = new GraphServices();
ResponseEntity<String> responseEntity;
//responseEntity = graphServices.getEmails(token); //Throws the same Unauthorized exception
HttpClient httpClient= HttpClients.createDefault();
HttpResponse response=httpClient.execute(httpGet);
//response contains Unauthorized access
HttpEntity entity=response.getEntity();
}
catch (MalformedURLException e){
e.printStackTrace();
}
catch (Exception e){
e.printStackTrace();
}
}
Here the Unauthorized error from the http.execute method
HttpResponseProxy{HTTP/1.1 401 Unauthorized [Content-Type:
application/json; charset=utf-8, Server: Microsoft-IIS/8.5,
request-id: 49ca360f-ab4b-42d5-a4b0-9676e4244c21, client-request-id:
49ca360f-ab4b-42d5-a4b0-9676e4244c21, x-ms-ags-diagnostic:
{"ServerInfo":{"DataCenter":"West
US","Slice":"SliceA","ScaleUnit":"003","Host":"AGSFE_IN_8","ADSiteName":"WST"}},
X-Powered-By: ASP.NET, Date: Tue, 06 Sep 2016 20:43:24 GMT,
Content-Length: 244] ResponseEntityProxy{[Content-Type:
application/json; charset=utf-8,Content-Length: 244,Chunked: false]}}
eyJ0eXAiOiJKV1QiLCJxcy76FRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyIsImtpZCI6IlliUkFRUlljRV9tb3RXVkpLSHJ3TEJiZF85cyJ9.eyJhdWdfsas32sub2ZmaWNlMzY1LmNvbSIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2YwMjYzMzUzLWFlYjItNGE4YS1iZThhLTc3Mzc3MmE2MGJlMy8iLCJpYXQiOjE0NzMxOTQ4MjIsIm5iZiI6MTQ3MzE5NDgyMiwiZXhwIjoxNDczMTk4NzIyLCJhcHBpZCI6IjhhNjc2ZjJkLWU1M2MtNDViNy05MzhhLTdiOTE1YjVkZTRiNiIsImFwcGlkYWNyIjoiMasdff4577dHMud2luZG93cy5uZXQvZjAyNjMzNTMtYWViMi00YThhLWJlOGEtNzczNzcyYTYwYmUzLyIsIm9pZCI6IjQ3NDhkZDE5LTAxOTUtNDcwOC04MTNkLTQxMTdhNDhlMTdmOCIsInN1YiI6IjQ3NDhkZDE5LTAxOTUtNDcwOC04MTNkLTQxMTdhNDhlMTdmOCIsInRpZCI6ImYwMjYzMzUzLWFlYjItNGE4YS1iZThhLTc3Mzc3MmE2MGJlMyIsInZlciI6IjEuMCJ9.BKt54345DIfv2WWT4pQ--Nuy-0aHkkht4332r7E4d5mP-EAEKmcQe7y0IPjkYGZTNhyNiG2tVAyb56Gcbessdsfewz_BNoAolTVukxttXc-pFY1_Ol5Adc8T5yio43ixfs88mrVRqZEHsb7c-wjO-otBXocZs8waYXdree83g1JtcnULs7bAGp3VBUhMjuJ2u87363Yq3lfse39_Pt6tRw]
(the token is something similar to this, just changed it to something similar for security)
Java walkthrough here (though for a web app using auth code flow): https://dev.outlook.com/restapi/tutorial/java
There's also this sample that uses client credential flow:
https://github.com/jasonjoh/java-calendar-demo
To authenticate in the daemon or service apps, we can use Client Credentials flow. After we register the app, we would get the secret. Then we can use the request below direct to get the app-only access token:
POST https://login.microsoftonline.com/<tenantId>/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=<clientId>
&client_secret=<clientSecret>
&resource=https://graph.microsoft.com
And to use the Office 365 access token, we can replace the resource with https://outlook.office.com. Here is a detail document about calling Microsoft Graph in a service or daemon app.
I have a strange situation going on while implementing Web service client.
Request fired from SOAP UI is success and the HTTP request is as below:
POST http://xxxxxxxxxx/xx/xx/xxxxx/xxxxx HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "CreateUserSoap"
Content-Length: 1490
Host: xxxxxxxxxxxxxxxxxxx.net
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Cookie: SMCHALLENGE=YES
Cookie2: $Version=1
Authorization: Basic ZHFhbgfdd6RFFQcdfgdm9vccQ=
<soap........./>
However when i fire the web service request from the application, for which i use apace cxf following HHTP Request is generated and i get a 403:Forbidden Error
ID: 1
Address: http://xxxxxxxxxx/xx/xx/xxxxx/xxxxx
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], Authorization=[Basic ZHFhbgfdd6RFFQcdfgdm9vccQ=], SOAPAction= ["CreateUserSoap"]}
Payload: <soap....... />
I am not sure if the apache - cxf is generating the right http header as expected by the server. the soap envelope is same in both cases.
Below is the implementing java client code:
ClientWs clientWS= new ClientWs ();
ClientWSPortType portType = clientWS.getClientWSPort();
BindingProvider provider = (BindingProvider) portType;
Header dummyHeader = new Header(new QName("http://clientWS/wsdl", "ClientWS"), documentBuilder.parse(new ByteArrayInputStream(xmlString2.getBytes("UTF-8"))).getDocumentElement() ); --parsing the soap mesage
headers.add(dummyHeader);
provider.getRequestContext().put(Header.HEADER_LIST, headers);
provider.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, user_name);
provider.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, pass_word);
Well, no one ansered neither was i able to do this with Apache CXF.
The turnaround was to use core java HttpURLConnection to achieve this.
A method something like this helped the cause ad post a webservice call without any framework.:
public HttpURLConnection getHttpConn(String webservice_url) throws IOException {
URL endpoint = new URL(webservice_url);
URLConnection connection = endpoint.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
byte[] encodedBytes = Base64.encodeBase64((getUsername()+":"+getPassword()).getBytes());
httpConn.setRequestMethod(getRequestMethod());
httpConn.setRequestProperty(HTTP_ACCEPT_ENCODING, getAccept_Encoding());
httpConn.setRequestProperty(HTTP_CONTENT_TYPE, getContentType());
httpConn.setRequestProperty(getContent_Length(), getContent_Length());
httpConn.setRequestProperty(HTTP_HOST, getHost());
httpConn.setRequestProperty(getConnection(), getConnection());
httpConn.setRequestProperty(HTTP_COOKIE2, getCookie2());
httpConn.setRequestProperty(HTTP_COOKIE, getCookie());
httpConn.setRequestProperty("Authorization", "Basic "+new String(encodedBytes));
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
return httpConn;
}
I use apache httpdefault client and execute post function as below
HttpResponse imToken = httpClient.execute(httpPostIM);
the response obtained is
HTTP/1.1 100 Continue
Connection: keep-alive
followed by:
HTTP/1.1 200 OK
Date: Tue, 30 Aug 2011 19:11:35 GMT
How do we handle this from client side ??
Here's the definition of response 100 from w3 and here's a good sample of what the response looks like. To quote:
The client SHOULD continue with its request. This interim response is used to inform the client that the initial part of the request has been received and has not yet been rejected by the server. The client SHOULD continue by sending the remainder of the request or, if the request has already been completed, ignore this response. The server MUST send a final response after the request has been completed. See section 8.2.3 for detailed discussion of the use and handling of this status code.
So if your client has already sent the entire request then it should just wait the server out until it gives a 200 or other "final" response.
According to the Apache HttpClient code, you don't have to do anything because the client ignores all 1XX response codes and continues to look for a final response. This is from commons-httpclient-3.1 in the class HttpMethodBase:
if ((status >= 100) && (status < 200)) {
if (LOG.isInfoEnabled()) {
LOG.info("Discarding unexpected response: " +
this.statusLine.toString());
}
this.statusLine = null;
}
If you are not seeing this behaviour then maybe you need to increase your client timeout? Maybe it isn't waiting long enough?