REST Response is {} - rest

I am new to REST. I have written a small REST resource and Whenever I try to invoke the REST service from POSTMAN, i get a empty response {} and status code 200
The Request :
http://localhost:8080/demo/managers
#GET
#Path("managers")
#Produces({"application/json"})
public Response getManagers() throws GeneralException, JSONException
{
JSONArray valueString = COMING_FROM_OTHER_METHOD();
System.out.println("==== "+valueString.toString());
return Response.ok(valueString,MediaType.APPLICATION_JSON).build();
}
The correct value I can see in System.out.println():
[{"display":"john","id":"003"},{"display":"hansi","id":"004"},{"display":"samy gayle","id":"005"}]
I want to a JSONArray Response but everytime I get an empty response
{}
But when modify the code like below it gives correct response
#GET
#Path("managers")
#Produces({"application/json"})
public String getManagers() throws GeneralException, JSONException
{
JSONArray valueString = COMING_FROM_OTHER_METHOD();
System.out.println("==== "+valueString.toString());
return valueString.toString();
}
Kindly Help. why am I getting {} when trying to return a Response object J

I would use domain objects rather than String instances:
class Manager {
private String id;
private String display;
... setters/getters ...
}
public ResponseEntity<ArrayList<Manager>> getManagers() throws GeneralException {
ArrayList<Manager> managers = COMING_FROM_OTHER_METHOD();
return new ResponseEntity<>(managers, HttpStatus.OK);
}

Related

Rest Assured: Why do I get IllegalStateException exception?

I am in the process of studying Rest-Assured framework.
I am using http://ziptasticapi.com free API for my drills.
When I call:
final static String BASE_URI = "http://ziptasticapi.com/";
final static String ADAK_ZIP_CODE = "99546"; //{"country":"US","state":"AK","city":"ADAK"}
final static String ATKA_ZIP_CODE = "99547";
public static final String GET_METHOD = "GET";
RestAssured.baseURI = BASE_URI;
String responseString = when().get(ADAK_ZIP_CODE).then()
.statusCode(200)
.and()
.extract()
.asString();
System.out.println(responseString);
I get the following string:
{"country":"US","state":"AK","city":"ADAK"}
as responseString value.
When I am trying:
RestAssured.baseURI = BASE_URI;
ZipData zipdata = when().get(ADAK_ZIP_CODE).then()
.statusCode(200)
.and()
.extract()
.as(ZipData.class);
public class ZipData {
public String country;
public String state;
public String city;
}
I crash on :
java.lang.IllegalStateException: Cannot parse object because no
supported Content-Type was specified in response. Content-Type was
'text/html;charset=UTF-8'.
Why is that? Could it be the rest returns an Html and not Json? How do I handle this?
Thanks!
First of all, keep in mind that REST Assured is a HTTP client primarily designed for testing HTTP APIs. So let me highlight that you shouldn't use REST Assured for anything other than testing.
Looks like the endpoint you are attempting to consume is returning a JSON document in the response payload, but the value of the Content-Type header is text/html;charset=UTF-8, so REST Assured cannot parse the response as a JSON document and convert it to an instance of ZipData. That's not what you expect from a sound HTTP API.
You could work around it and write a filter to override the Content-Type header, as show below:
public class OverrideContentTypeFilter implements Filter {
#Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
Response next = ctx.next(requestSpec, responseSpec);
return new ResponseBuilder().clone(next).setContentType(ContentType.JSON).build();
}
}
Then use it as follows:
ZipData zipdata =
given()
.filter(new OverrideContentTypeFilter())
.when()
.get(uri)
.then()
.statusCode(200)
.extract()
.as(ZipData.class);

400 error when making post request to Spring server

Hi I'm very new to Swift and trying to make a simple application.
I'm using 'alamofire 5 beta 6' to make a request.
Here is some code below
-code for making post request
var json:JSON = JSON(["id":id.text, "password":enteredPassword])
var parameters: Parameters = ["id":id.text, "password":enteredPassword]
let headers:HTTPHeaders = [ "Content-Type":"application/json"]
AF.request("http://127.0.0.1:8080/user", method: .post, parameters: parameters, encoding: URLEncoding.httpBody, headers: headers).responseJSON{
response in
print("response : \(response)")
}
-code for Spring Framework
#RequestMapping(value="user", method=RequestMethod.POST)
public JSONObject addUser(
#RequestBody Memberinfo member,
HttpServletRequest request) {
JSONObject result = new JSONObject();
return result;
}
-Memberinfo.java that is used in controller to retrieve #RequestBody
public class Memberinfo {
String id;
String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
In Swift code, I set parameter id and password to retrieve it back in Spring framework.
However, right after I make a request, Alamofire responses with message
response : success({
error = "Bad Request";
message = "JSON parse error: Unrecognized token 'id': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'id': was expecting ('true', 'false' or 'null')\n at [Source: (PushbackInputStream); line: 1, column: 4]";
path = "/user";
status = 400;
timestamp = "2019-06-09T05:46:07.417+0000";
})
I think the parameter should be sent as following
var parameters: Parameters = {"id":id.text, "password":enteredPassword}
Another important thing that you don't need to have a JSONObject as a response type for your endpoint you can just annotate your endpoint with #ReponseBody to have a json response
#RequestMapping(value="user", method=RequestMethod.POST)
#ResponseBody
public ResponseEntity<JSONObject> addUser(
#RequestBody Memberinfo member,
HttpServletRequest request) {
JSONObject result = new JSONObject();
return result;
}
Always use something like Postman or RestClient to test your endpoint before calling this endpoint from an external source

Spring boot using wrong message convertor

I have a rest endpoint like below which is supposed to accept an XML input, do some processing on it and then return a response in XML as well.
#RequestMapping(value = "/rest/v1/test/listener", method = RequestMethod.POST)
public ResponseEntity<MyResponseType> processBooking(#RequestBody MyRequest myRequest) throws JAXBException {
MyResponseType response = myService.process(myRequest);
// ... do something with it and generate 'response'
return new ResponseEntity<>(response, HttpStatus.OK);
}
And MyRequest class looks like below which is autogenerated via jaxb and an external xsd which I cannot change (details omitted from the class)
/**
* MyRequest
*/
public class MyRequest {
#XmlElement(required = true)
#XmlSchemaType(name = "string")
protected SomeEnum someEnum;
...
#XmlType(name = "SomeEnum")
#XmlEnum
public enum SomeEnum {
ACTIVITY,
DEPOSIT,
EQUIPMENT,
FEE,
MISC,
PROTECTION,
RENTAL,
TAX,
DISCOUNT;
public static SomeEnum fromValue(String v) {
return valueOf(v);
}
public String value() {
return name();
}
}
}
The problem is that when I try to run it, I get the following error message
2018-04-09 11:47:59.378 WARN 2702 --- [ main]
.w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP
message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Can not construct instance of MyRequest.SomeEnum: no
String-argument constructor/factory method to deserialize from String
value ('MISC'); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of MyRequest.SomeEnum: no String-argument constructor/factory
method to deserialize from String value ('MISC')
A sample xml that I send as input is
<myRequest>
...
<advertiserAssignedId>19ABC12331</advertiserAssignedId>
<listingExternalId>ABC123</listingExternalId>
<unitExternalId>ABC123</unitExternalId>
<someEnum>
<name>MISC</name>
<feeType>MISC</feeType>
...
</someEnum>
...
</myRequest>
You have to specify what is your endpoint consuming using the consumes attribut .
When you post the request to your endpoint, don't forget to set the Content-type header to application/xml

Apache HttpClient - REST API: Issue in converting response to customized object which is put as SerializableEntity

I am using Apache HttpClient to put/get customized object using REST APIs. Below is the sample code. My putObject() method works fine and I could serialize Person object and put properly. However, while getting the object, I got below error:
Exception in thread "main" java.lang.ClassCastException: [B cannot be cast to Person at MyTest.demoGetRESTAPI(MyTest.java:88) at MyTest.main(MyTest.java:21)
Seems the code to build Person object out of response entity is not correct
HttpEntity httpEntity = response.getEntity();
byte[] resultByteArray = EntityUtils.toByteArray(httpEntity);
Person person = (Person)SerializationUtils.deserialize(resultByteArray);
Am I doing somthing wrong while getting byte[] array and converting to Person object. Please help me out to solve this issue.
Complete Example Program:
import java.io.Serializable;
import org.apache.commons.lang.SerializationUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.SerializableEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class MyTest {
public static void main(String[] args) throws Exception {
putObject();
getObject();
}
public static void putObject() throws Exception
{
HttpClient httpClient = new DefaultHttpClient();
Person person = new Person();
person.setName("Narendra");
person.setId("1");
try
{
//Define a postRequest request
HttpPut putRequest = new HttpPut("http://localhost:9084/ehcache-server/rest/screeningInstance/2221");
//Set the API media type in http content-type header
putRequest.addHeader("content-type", "application/x-java-serialized-object");
//Set the request put body
SerializableEntity personSEntity = new SerializableEntity(SerializationUtils.serialize(person));
putRequest.setEntity(personSEntity);
//Send the request; It will immediately return the response in HttpResponse object if any
HttpResponse response = httpClient.execute(putRequest);
//verify the valid error code first
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 201)
{
throw new RuntimeException("Failed with HTTP error code : " + statusCode);
}
}
finally
{
//Important: Close the connect
httpClient.getConnectionManager().shutdown();
}
}
public static void getObject() throws Exception
{
DefaultHttpClient httpClient = new DefaultHttpClient();
try
{
//Define a HttpGet request; You can choose between HttpPost, HttpDelete or HttpPut also.
//Choice depends on type of method you will be invoking.
HttpGet getRequest = new HttpGet("http://localhost:9084/ehcache-server/rest/screeningInstance/2221");
//Set the API media type in http accept header
getRequest.addHeader("accept", "application/x-java-serialized-object");
//Send the request; It will immediately return the response in HttpResponse object
HttpResponse response = httpClient.execute(getRequest);
//verify the valid error code first
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200)
{
throw new RuntimeException("Failed with HTTP error code : " + statusCode);
}
//Now pull back the response object
HttpEntity httpEntity = response.getEntity();
byte[] resultByteArray = EntityUtils.toByteArray(httpEntity);
Person person = (Person)SerializationUtils.deserialize(resultByteArray);
}
finally
{
//Important: Close the connect
httpClient.getConnectionManager().shutdown();
}
}
}
class Person implements Serializable{
String name;
String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return "Person [name=" + name + ", id=" + id + "]";
}
}
I got the solution. It was mistake in my code:
While putting object, I have written below code. That was doing two time serialization. First from Person object to byte[] and second from byte[] to byte[].
SerializableEntity personSEntity = new SerializableEntity(SerializationUtils.serialize(person));
putRequest.setEntity(personSEntity);
This is the right approach:
SerializableEntity personSEntity = new SerializableEntity(person);
putRequest.setEntity(personSEntity);
After getting binary from REST, code should be like below to get Object:
HttpEntity httpEntity = response.getEntity();
InputStream inputStream = null;
try {
inputStream = httpEntity.getContent();
Person p = (Person) SerializationUtils.deserialize(inputStream);
System.out.println("Person:" + p.getName());
}
finally {
inputStream.close();
}
This worked like CHARM !!

Return more that one entity in RESTful response?

I'm developing a RESTful websevices project, my question is simple,
is there a way to return both 'File' and 'JSON' entities in the same response?
e.g.: suppose I have this method:
#GET
#Path("downloadFile")
#Consumes(MediaType.TEXT_PLAIN)
public Response downloadLogStream( ..... ) {
.....
Response.ok(resultFile);
}
but I need to return another entity beside the file itself without adding additional Headers.
is that possible?
You can send only response but that can be a complex object. Wrap result/json and status in response.
return Response.status(200).entity(result).build();
More here
#GET
#Path("downloadFile")
#Consumes(MediaType.TEXT_PLAIN)
public Response downloadLogStream( ..... ) {
// Assuming result is json string
String result = " JSON is "+jsonObj;
return Response.status(200).entity(result).build();
}
}
File download
private static final String FILE_PATH = "pathTo:\\filename. Zip";
#GET #Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile()
{
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=newfile.zip");
return response.build(); }