Decompressing REST response with GZIPInputStream - grails

I'm trying to decompress a gzip:ed response i receive from a REST service:
Content-Encoding=[gzip], Content-Type=[application/json], Content-Length=[710] ...
I'm using the Grails REST Client Builder Plugin:
def response = new RestBuilder().get(HOST + "/api/..."){
contentType "application/json"
accept "application/json"
}
The returned response is a Spring ResponseEntity. I'm trying to decompress the data using GZIPInputStream:
String body = response.getBody()
new GZIPInputStream(new ByteArrayInputStream(body.getBytes())).text
This fails to Caused by ZipException: Not in GZIP format
Obviously there is something I'm doing wrong, but I can't figure out what. All advice is appriciated.

If you really need to keep using the Rest Client Builder you only need to modify your client code slightly:
def response = new RestBuilder().get(HOST + "/api/..."){
contentType "application/json"
accept byte[].class, "application/json" }
Note the extra parameter in the accept call - byte[].class - which signifies that RestTemplate should refrain from any parsing of the response.
To decompress you can now do:
new GZIPInputStream(new ByteArrayInputStream(response.body))
Yeah, I know, already answered with accept but some might still find it helpful in case switching Rest components is not an option.

I never managed to get it to work with grails / groovy libraries, so i switched to spring and httpcomponents:
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<String> response = restTemplate.exchange(
"some/url/", HttpMethod.GET, new HttpEntity<Object>(requestHeaders),
String.class);
Which decoded gzip automatically and thus there are no longer any need for manual decoding.

Related

RestAssured - how to send a request without Content-Type?

I am using RestAssured to send a request:
Map<String, Object> headers = new HashMap<>();
headers.put("Accept", "*/*");
headers.put("Accept-Encoding", "gzip, deflate, br");
headers.put("Connection", "keep-alive");
Response response = RestAssured.given().baseUri(BASE_URL)
.headers(headers)
.log().all()
.post(URL_PREFIX + "/documents/request/" + username);
However, in the log I see that 1 more header was automatically added:
Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1
And I get 415 error.
Is it possible to send a request without Content-Type? I mean, without this header at all; if the request is sent with Content-Type equal to empty line, there is still a 400 error; the only way to make it work is to send the request without this header.
Seems like there is a bug in the RestAssured framework that is still open (I verified that in 4.3.3).
// https://mvnrepository.com/artifact/io.rest-assured/rest-assured
testImplementation group: 'io.rest-assured', name: 'rest-assured', version: '4.3.3'
Founded out, when creating negative tests for a API. Content type below is automatically generated when trying to send request.
Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1
Bug defined here:
https://github.com/rest-assured/rest-assured/issues/656
https://github.com/rest-assured/rest-assured/issues/986

Rest Assured basic auth issue

I have an endpoint which works perfectly fine when I use Postman with Basic Auth. However, when I tried it in Rest Assured it returns 401. I have tried both different auth methods in rest assured and none of them worked for me so far. Need help!
RequestSpecification requestSpec;
String baseURI = "http://qa3-phoenix.labcorp.com";
String basePath = "/phx-rest/healthcheck/ping";
RestAssured.useRelaxedHTTPSValidation();
RestAssured.baseURI = baseURI;
requestSpec = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.build();
Response response = RestAssured
.given()
.spec(requestSpec)
.auth().basic("username","password")
.when()
.get(basePath)
.then()
.extract().response();
One can use directly the Authorization header with base64 encoded username and password and omit the auth() part.
Code example:
String authBasic = Base64.encode(String.format("%s:%s", username, password));
rest()
.header("Authorization", String.format("Basic %s", authBasic))
useRelaxedHTTPSValidation() is a workaround when the server is not using a valid certificate or you bump into SSLPeerUnverifiedException. In most of the scenarios this does not happen.
So try removing useRelaxedHTTPSValidation().
Can you also try the below approach:
While creating your RequestSpecification, can you add an object of authentication scheme to your RequestSpecification and then use that to create http requests.
RequestSpecBuilder req = new RequestSpecBuilder();
PreemptiveBasicAuthScheme auth = new PreemptiveBasicAuthScheme();
auth.setUserName("");
auth.setPassword("");
req.setAuth(auth);
req.build();
May be you can think of creating your RequestSpec from a separate class or package for better re-use.
Let me know if this helps, or the stacktrace.

Setting content type/ encoding in Jersey REST Client

HI I have been trying to call REST POST API using jersey REST Client. The API is docs is
URL:
METHOD: POST
Header Info:-
X-GWS-APP-NAME: XYZ
Accept: application/json or application/xml
My Sample Jersey client code is
Client client = Client.create();
WebResource resource=client.resource(URL);
resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML);
resource.type(javax.ws.rs.core.MediaType.APPLICATION_XML);
resource.type("charset=utf-8");
ClientResponse response = resource.post(ClientResponse.class,myReqObj);
I have been trying this code variation since last 1 week and it is not working. Any help in this regard is highly appreciated.
The tricky part is that the WebResource methods follows the Builder design pattern so it returns a Builder object which you need to preserve and carry on as you call further methods to set the full context of the request.
When you do resource.accept, it returns something you don't store, so it's lost when you do resource.type and therefore only your last call takes effect.
You'd typically set all the criterias in one line, but you could also save the output in a local variable.
ClientResponse response = client.resource(URL)
.accept(MediaType.APPLICATION_XML)
.type(MediaType.APPLICATION_XML)
.post(ClientResponse.class,myReqObj);
I do like that.
Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(a, "application/json; charset=UTF-8"));
here, 'a' is account class instance which like
#XmlRootElement
public class account {
...
...
}

Invoke WCF Data Services Service Operation from iOS

How do I invoke a Service Operation in WCF from iOS?
I have a Service Operation defined in my WCF Data Service (tied to a stored procedure in my DB schema) that I need to invoke from iOS. Say I've got the following declaration in my .svc.cs file:
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public IQueryable<Foo> GetFoos(int param1, DateTime param2, string param3)
{
return CurrentDataSource.GetFoos(param1, param2, param3).AsQueryable();
}
And I've got it set up with the proper rights in InitializeService:
config.SetServiceOperationAccessRule("GetFoos", ServiceOperationRights.AllRead);
When I try to invoke this via HTTP POST from iOS, I get back an error wrapped in JSON:
Bad Request - Error in query syntax.
It seems like it doesn't like how I'm passing my parameters. I'm passing them JSON-encoded (using NSJSONSerialization to turn an NSDictionary into a JSON string) in the request body of a POST request. The same method works on another web service (.svc) not connected to WCF that has operations annotated the same way.
An answer to another question of mine in a similar vein suggests that data formats can be negotiated between client and server, and I've read that dates are a pain to format, so maybe it's my DateTime parameter that's a problem. But I've tried both the JSON format (\/Date(836438400000)\/ and /Date(836438400000)/) and the JSON Light format (1996-07-16T00:00:00) to no avail.
So my question is this: what is the proper way to invoke this operation? If I need to have my app tell the server what format to expect, how do I do that?
Update: I tried using the format datetime'1996-07-16T00:00:00' as mentioned in this question. Same error.
Update 2: The MSDN page for Service Operations seems to suggest that nothing besides Method = "POST" is supported when annotating the WebInvoke for a Service Operation. I tried removing everything from what is quoted in the above code and setting the method to POST. Same error.
Update 3: On Pawel's suggestion, I made a new Service Operation on my Data Service just like this:
[WebInvoke(Method = "POST")]
public IQueryable<string> GetFoos()
{
List<string> foos = new List<string>();
foos.Add("bar");
return foos.AsQueryable();
}
I was able to make it work in Fiddler's Composer pane by setting the method to POST, adding accept:application/json;charset=utf-8 and Content-Length:0 to the headers. Then I added a single int parameter to the operation (called param1). I set the body of my request in Fiddler to {"param1":"1"} and ran it (and Fiddler automatically updated my content-length header), and got the same error. I changed the type of my parameter to string and ran my request again and it worked. So my problem seems to be non-string types.
You need to send parameters in the Url and not in the request body.

I am sending data over HTTPS but the server side says it is not receiving it

I create an application that sends some data to a secured network.
At the server side they need the data as JSON object. For that am creating the data as JSON object and writing that data in the OutputStream of the connection.
But the response from the server side telling it is not getting the data that I am passing.
The code snippet that am using is something like given below:
HttpsConnection _connection = (HttpsConnection)Connector.open("https://gmail.com/",Connector.READ_WRITE, true); _connection.setRequestMethod(HttpsConnection.POST);
_connection.setRequestProperty("If-Modified-Since", "29 Oct 1999 19:43:31 GMT");
_connection.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
_connection.setRequestProperty("Content-Language", "en-US");
_connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
byte[] postData = jsonObject.toString().getBytes("UTF-8");
_connection.setRequestProperty("Content-Length", Integer.toString(postData.length));
_connection.setRequestProperty("jsondata",jsonObject.toString());
OutputStream os = _connection.openOutputStream();
os.write(postData);
os.flush();
Please help me to solve the issue.
I guess the reason is "Content-Type" => "application/x-www-form-urlencoded". This type of a POST exists for sending a list of key=value pairs. So the server on its side will parse the post data in terms of key=value pairs. I believe in your case it just fails to parse the got post data, because you don't send the data in the key=value pairs form (instead you just pour the entire json string jsonObject.toString().getBytes("UTF-8") in it).
So basically you need to form a key value pair "json=YOUR_JSON_HERE". Then on the server you will get your data as the json parameter value:
URLEncodedPostData encPostData = new URLEncodedPostData("UTF-8", false);
encPostData.append("json", jsonObject.toString());
byte[] postData = encPostData.toString().getBytes("UTF-8");
Another option (and BTW it would be the most proper way to do this particular task) would be to use "multipart/form-data" POST type. However it will be a bit harder to implement it if you've never done that before on BB.
You have to append appropriate suffix to to your url
eg: If you use simulator use:https://gmail.com/;deviceside=true etc
I have same this problem but finally find solution:
HttpConnection c = (HttpConnection)Connector.open(url);
c.setRequestMethod(HttpConnection.POST);
c.setRequestProperty(
HttpProtocolConstants.HEADER_CONTENT_TYPE, PostData.getContentType());
c.setRequestProperty(
HttpProtocolConstants.HEADER_CONTENT_LENGTH,String.valueOf(oPostData.size()));
c.setRequestProperty("Content-Length", Integer.toString(oPostData.size()));
c.setRequestProperty("Content-Type","application/json");
byte [] postDataBytes = jobj.toString().getBytes("UTF-8");
os = c.openOutputStream();
os.write(postDataBytes);
os.flush();

Resources