setting content type in rest assured - java

I'm trying to invoke a rest call using rest assured. My API accepts, "application/json" as content type and I need to set in the call. I set the content type as mentioned below.
Option 1
Response resp1 = given().log().all().header("Content-Type","application/json")
.body(inputPayLoad).when().post(addUserUrl);
System.out.println("Status code - " +resp1.getStatusCode());
Option 2
Response resp1 = given().log().all().contentType("application/json")
.body(inputPayLoad).when().post(addUserUrl);
The response I get is "415" (indicates that "Unsupported media type ").
I tried invoking the same api using plain java code and it works. For some mysterious reason, I cudn't get it working through RA.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(addUserUrl);
StringEntity input = new StringEntity(inputPayLoad);
input.setContentType("application/json");
post.setEntity(input);
HttpResponse response = client.execute(post);
System.out.println(response.getEntity().getContent());
/*
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println("Output -- " +line);
}

I faced similar issue while working with rest-assured 2.7 version. I tried setting both the contentType and also accept to application/json but it didn't work. Adding carriage feed and new line characters at the end as the following worked for me.
RestAssured.given().contentType("application/json\r\n")
The API seems to be missing to add new line characters after Content-Type header due to which the server is not able to differentiate between the media type and the rest of the request content and hence throwing the error 415 - "Unsupported media type".

Here is the complete POST example using CONTENT_TYPE as JSON.
import io.restassured.http.ContentType;
RequestSpecification request=new RequestSpecBuilder().build();
ResponseSpecification response=new ResponseSpecBuilder().build();
#Test
public void test(){
User user=new User();
given()
.spec(request)
.contentType(ContentType.JSON)
.body(user)
.post(API_ENDPOINT)
.then()
.statusCode(200).log().all();
}

Give a try
given().contentType(ContentType.JSON).body(inputPayLoad.toString)

This might possibly be the case with your test. Try this.
https://github.com/rest-assured/rest-assured/wiki/Usage#avoid-adding-the-charset-to-content-type-header-automatically
Avoid adding the charset to content-type header automatically
By default REST Assured adds the charset header automatically. To
disable this completely you can configure the EncoderConfig like this:
RestAssured.config = RestAssured.config(config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false));

As mentioned in previous posts there is a method:
RequestSpecification.contentType(String value)
I did not work for me too. But after upgrade to the newest version (in this moment 2.9.0) it works. So please upgrade :)

I was facing something similar and after some time we noticed the problem was actually coming from the server side. Please check your call on Postman and see if when it's triggered you need to change it from HTML to JSON. If you need to do that, the backend may need to force the response to be in JSON format by adding its content type. Even if it's encoded in JSON you're still may need to do that.
Thats the line of code we added:
header('Content-type:application/json;charset=utf-8');
.
public function renderError($err){
header('Content-type:application/json;charset=utf-8');
echo json_encode(array(
'success' => false,
'err' => $err
));
}
And that's what was happening on the backend:
Hope that can help somehow. :)

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import static org.hamcrest.Matchers.is;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
public class googleMapsGetLocation {
#Test
public void getLocation() {
RestAssured.baseURI = "https://maps.googleapis.com";
given().param("location", "-33.8670522,151.1957362")
.param("radius", "500")
.param("key", "AIzaSyAONLkrlUKcoW-oYeQjUo44y5rpME9DV0k").when()
.get("/maps/api/place/nearbysearch/json").then().assertThat()
.statusCode(200).and().contentType(ContentType.JSON)
.body("results[0].name", is("Sydney"));
}
}

For your First option can you please try adding this header too and sending the request?
.header("Accept","application/json")

Related

Wiremock encoding issue

I'm currently trying to use wiremock to mock the result of http calls in my unit tests, and when I try to get the response body, I got some encoding issues.
I write one methode to stub a post methode
public static void setupMockExecutionResponse(WireMockServer mockService) throws IOException {
mockService.stubFor(WireMock.post(WireMock.urlEqualTo("/reportExecutions"))
.willReturn(WireMock.aResponse()
.withStatus(HttpStatus.OK.value())
.withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE+"; charset=utf-8")
.withHeader("set-cookie", "JSESSIONID=1111111111111; SERVERID=jasper")
.withBody(
copyToString(
JasperClientMock.class.getClassLoader().getResourceAsStream("payload/execution-response.json"),
StandardCharsets.UTF_8))));
}
As you can see I specified that the charset of the response body is UTF-8, and in the header I add it too.
The json file used as the response is also encoded in UTF-8
{
"status":"ready",
"totalPages":1,
"requestId":"217f7dc9-47c4-4c44-bada-7e29b653887b",
"reportURI":"/test/test/test/test/export_test",
"exports":[
{
"status":"ready",
"outputResource":{
"contentType":"application/pdf",
"fileName":"export_test.pdf",
"outputFinal":true,
"outputTimestamp":0
},
"id":"6ca0038f-94ff-4bd9-bdf4-6a35259fd05e"
}
]
}
I expect when I make the post request to get the header specified in the setUp of the mock and the json string corresponding at my file.
feign.Response r = jasperFeignClient.executeReport(headerMap, requestBody);
checkResponseStatut(r.status(), EXECUTION_STEP, documentJasperRequest.getUrlReport(), requestBody);
getCookie(r, cookies);
String execResponse = IOUtils.toString(r.body().asInputStream(), String.valueOf(StandardCharsets.UTF_8));
I have the good return code (200), the cookies that I set, but my response body is messed up and look like this
So when I try to convert it to a java object I have parsing error, because it can't find the begining character of the json.
I even tryed to hard code the json string directly in the body of the stub, but that didn't change a things.
EDIT
When I make a direct call to the stubbed endpoint in my test, the encoding is good
#Test
public void testGetPDF(){
Response response = given().when().post("http://localhost:9561/reportExecutions");
String status = response.jsonPath().get("status");
System.out.println(status);
assertEquals(status, "ready");
}
It's only when I go into the class where the call is made that i got encoding issues.
It looks like your call via the Jasper client is by default setting accept-encodig:gzip (or something similar) and WireMock is therefore returning a gzipped body.
You should be able to resolve the issue by doing one of: a) disabling gzip in WireMock, b) disabling gzip in your client config, or c) ungzipping the body before attempting to parse it.
After updating all my pom dependencies to their latest version solved this encoding issue.

Get answer from rest server with javax.ws.rs.client [duplicate]

Having some sort of proxy between a mobile app and a web-service, we are puzzled by the response when issuing a post request. We receive response with status 200: OK. But we can not find/extract the JSON response body.
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(WEBSERVICE_BASE_LOCATION + "mobileDevices?operatorCode=KPNSCP");
String jsonString = "{\"osVersion\":\"4.1\",\"apiLevel\":16,\"devicePlatform\":\"ANDROID\"}";
Builder builder = webTarget.request();
Response response = builder.post(Entity.json(jsonString));
We are using JAX-RS.
Can someone please provide some hints to extract the JSON body (String) from the server response?
Try this:
String output = response.getEntity(String.class);
EDIT
Thanks to #Martin Spamer to mention that it will work for Jersey 1.x jars only. For Jersey 2.x use
String output = response.readEntity(String.class);
I just found a solution for jaxrs-ri-2.16 - simply use
String output = response.readEntity(String.class)
this delivers the content as expected.
For my use case, none of the previous answers worked because I was writing a server-side unit test which was failing due the following error message as described in the Unable to Mock Glassfish Jersey Client Response Object question:
java.lang.IllegalStateException: Method not supported on an outbound message.
at org.glassfish.jersey.message.internal.OutboundJaxrsResponse.readEntity(OutboundJaxrsResponse.java:145)
at ...
This exception occurred on the following line of code:
String actJsonBody = actResponse.readEntity(String.class);
The fix was to turn the problem line of code into:
String actJsonBody = (String) actResponse.getEntity();
I also had the same issue, trying to run a unit test calling code that uses readEntity. Can't use getEntity in production code because that just returns a ByteInputStream and not the content of the body and there is no way I am adding production code that is hit only in unit tests.
My solution was to create a response and then use a Mockito spy to mock out the readEntity method:
Response error = Response.serverError().build();
Response mockResponse = spy(error);
doReturn("{jsonbody}").when(mockResponse).readEntity(String.class);
Note that you can't use the when(mockResponse.readEntity(String.class) option because that throws the same IllegalStateException.
Hope this helps!
Acording with the documentation, the method getEntity in Jax rs 2.0 return a InputStream.
If you need to convert to InputStream to String with JSON format, you need to cast the two formats.
For example in my case, I implemented the next method:
private String processResponse(Response response) {
if (response.getEntity() != null) {
try {
InputStream salida = (InputStream) response.getEntity();
StringWriter writer = new StringWriter();
IOUtils.copy(salida, writer, "UTF-8");
return writer.toString();
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
return null;
}
why I implemented this method.
Because a read in differets blogs that many developers they have the same problem whit the version in jaxrs using the next methods
String output = response.readEntity(String.class)
and
String output = response.getEntity(String.class)
The first works using jersey-client from com.sun.jersey library and the second found using the jersey-client from org.glassfish.jersey.core.
This is the error that was being presented to me:
org.glassfish.jersey.client.internal.HttpUrlConnector$2 cannot be cast to java.lang.String
I use the following maven dependency:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
What I do not know is why the readEntity method does not work.I hope you can use the solution.
Carlos Cepeda
Realizing the revision of the code I found the cause of why the reading method did not work for me. The problem was that one of the dependencies that my project used jersey 1.x.
Update the version, adjust the client and it works.
I use the following maven dependency:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
Regards
Carlos Cepeda

HTTP request being sent correctly but returns incorrect value/result

I'm trying to send an http request to bing's spell checking api using a GET request. I checked my parameters and headers on https://www.hurl.it/ and it returned a proper json with the spelling errors properly, however when I send the request from my java app it returns this json with NO spelling errors detected (therefore, text parameter HAS to be empty somehow). I'm definitely passing the correct key in the header because that part isn't sending an error and the code is 200 (success).
My string: "my funger is harting me"
My code returned:
{"_type":"SpellCheck","flaggedTokens":[]}
Hurl.it returned:
{
"_type":"SpellCheck",
"flaggedTokens":[
{
"offset":3,
"token":"funger",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"finger",
"score":0.903614003311793
}
]
},
{
"offset":13,
"token":"harting",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"hurting",
"score":0.903614003311793
}
]
}
]
}
This is my java code using Apache's HTTPClient library:
(note: "command.getAfter()" is the passed string I mentioned above. I debugged it and even hard coded a string to test it out. Same output obviously.)
HttpClient httpclient = HttpClients.createDefault();
try {
URIBuilder builder = new URIBuilder("https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/");
builder.setParameter("text", command.getAfter());
URI uri = builder.build();
HttpGet request = new HttpGet(uri);
request.setHeader("Ocp-Apim-Subscription-Key", "XXXXXXXX");
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
EDIT: It turns out the URI returned in the request object returns this:
https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=my+funger+is+harting+me
So the parameter is not empty? But when fed no text parameter in hurl.it, the api returns an error of no parameters. When the text parameter is a space " ", it returns an identical result to mine. Unsure what this means since the URI seems to be valid and not empty and my subscription key is working because i would get an error if it weren't...
EDIT: I'm starting to suspect the Apache library is ignoring the parameters I'm passing in HttpGet(uri). I'm unsure, but I'm going to try a different solution to send the request with a header and see what happens.
EDIT: I tried the following code below:
String url = "https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=" + command.getAfter().replace(" ", "+");
try {
URL request_url = new URL(url);
//URIBuilder uri = new URIBuilder("https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/");
//uri.setParameter("text", command.getAfter());
HttpURLConnection con = (HttpURLConnection) request_url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Ocp-Apim-Subscription-Key", Keys.BING_SPELL_CHECK_API);
con.setConnectTimeout(100000);
con.setReadTimeout(100000);
con.setInstanceFollowRedirects(true);
String theString = IOUtils.toString(con.getInputStream(), "UTF-8");
System.out.println(theString);
} catch (IOException e) {
e.printStackTrace();
}
It returned the same result as the Apache one... :/ What else should I try?
EDIT:
This is the output of the request as well:
https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=my+funger+is+hartingme - [Ocp-Apim-Subscription-Key: <XXXXXXXXXXXX>]
HTTP/1.1 200 OK - en_US
{"_type": "SpellCheck", "flaggedTokens": []}
I don't get it.... Why is the json outputted empty when hurl.it returns the correct json for this same request? Is this a java issue or something?
EDIT:
I just tried UniRest's api. Exact same result... What am I doing wrong here?!
I'm so lost...
Separate Issue:
I do want to note the following: When I set the bing api's version to 7.0, I get the following error:
Received http status code 401 with message Access Denied and body {"message":"Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription.","statusCode":401}
This is not the case with v5.0. I'm getting the correct key from my Azure portal. (The page called Keys and lists 2 keys you can use and regenerate)
Answer to getting v7.0 to work:
This is not the case with v5.0. I'm getting the correct key from my Azure portal. (The page called Keys and lists 2 keys you can use and regenerate)
You get 2 keys per version. So if you are seeing 2 keys, they are likely both for v5.0. It should explicitly mention v7.0.
There should be different sections, also with different endpoints.
Use these in combination with each other to get the desired result.

codenameone POST request BODY

I am using CodenameOne to send a POST request to a REST API.
It works perfectly with the GET because I do not have to pass a BODY with the message.
Please can someone tell me how to pass a BODY with my post message?
Here is the code I am using to connect ...
try {
ConnectionRequest connReq = new ConnectionRequest();
connReq.setPost(true);
connReq.addRequestHeader("Authorization", "54321);
connReq.addRequestHeader("client_id","12345");
connReq.addRequestHeader("Content-Type","application/json");
connReq.setUrl("https://myapi.com/connect");
connReq.setHttpMethod("POST");
NetworkManager.getInstance().addToQueueAndWait(connReq);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(connReq.getResponseData()), "UTF-8"));
return result;
}
catch(Exception err) {
System.err.println(err);
return null;
}
I have found some documentation here - but I can't quite understand what they are telling me ...
https://www.codenameone.com/javadoc/com/codename1/io/ConnectionRequest.html#buildRequestBody-java.io.OutputStream-
Thanks
If you want a standard "FORM" style post which is what you would get if you have fields in an HTML form just use addArgument as you would with GET. It will work with POST just fine.
If you want to "hardcode" your body e.g. some webservices expect JSON to be the body of the request just write it into the output stream in the buildRequestBody method you found.

JUnit for REST: Cannot POST data

I want to write a JUnit class for a REST endpoint.
This is my REST method. It works fine.
#POST
#Path("create")
#Produces(APPLICATION_JSON)
public String create(#QueryParam("parentId") String parentId, #QueryParam("name") String name) {
//do sth.
return "{\"status\": \"SUCCESS\"}";
}
Now my JUnit test looks like that, which doesn't work, because I don't know how to POST my data in the right way:
#Test
public void testCreate() {
Client client = ClientBuilder.newClient();
WebTarget wt = client.target(REST_MENU_URL + "create");
String queryParams = "parentId=1&name=NEW_JUnit_NEW";
// In the line below, I want to POST my query parameters, but I do it wrong
Response response = wt.request().post(Entity.entity(queryParams, APPLICATION_JSON), Response.class);
// The response has a 500, because the query parameters are all NULL!
assertEquals("Http code should be 200", 200, response.getStatus());
}
So how do I have to change the line with the 'Response' to make it work?
The problem is, that the query parameters (parentId and name) don't get transmitted (response = wt.request().post(...)).
I tried to POST form parameters too, but no success here either. Just like that:
Form form =new Form().param("parentId", "4").param("name", "NEW_JUnit_NEW");
Response response = wt.request().post(Entity.entity(form, APPLICATION_JSON), Response.class);
Thanks,
Bernhard
Check out the Jersey Client documentation, in particular section 5.3.4 on targeting resources.
Query parameters form a part of the URI of the resource, they're not part of the body of the document posted to the resource. You're seeing null in your resource because you're not filling in the query parameters in the URI, you're posting them as the body. You need to tell Jersey to put them in the URI...
WebTarget wt = client.target(REST_MENU_URL + "create").queryParam("parentId", 1).queryParam("name", "NEW_JUnit_NEW");
You'll also need to ensure that your POST request sets the Accept header to allow application/json (by calling the accept(...) method after calling request()) and you're going to need to construct some kind of Entity to pass to the post(...) method - the problem here is that your resource is not consuming the entity body but the client API expects you to send something - this is a code smell which suggests your API is not particularly ReSTful. You can probably get away with some kind of empty body constructed from an empty string. It should look a bit like this...
Response response = wt.request().accept(MediaType.APPLICATION_JSON).post(Entity.text(""))
Alternatively, you could look into converting your API so that it accepts a JSON document and move the query parameters into that document.

Categories