Spring REST Endpoint Returning String instead of JSON - rest

The following endpoint returns a username as a string.
How would I structure it to return a json object that contains a key with that string as its value (e.g., {"user":"joeuser"}?
#GetMapping(value = "/getUser", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getUser() {
HttpHeaders responseHeaders = new HttpHeaders();
CustomUserAuthentication authentication = (CustomUserAuthentication) SecurityContextHolder.getContext().getAuthentication();
return ResponseEntity.ok().headers(responseHeaders).body(String.valueOf(authentication.getPrincipal()));
}

Using some Json library (like gson), build the Json object and return it in the body instead of the String. Make sure response content-type is application/json
You can also manually build the String that looks like Json but content to must be as above.

Spring can do what you want, but you need to return something that Spring needs to marshal into JSON. From my previous answer: https://stackoverflow.com/a/30563674/48229
#RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public Map<String, Object> bar() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("test", "jsonRestExample");
return map;
}

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);

Rest API return output in different formats

I have a Rest api that returns list of emailIds given a list of customerIds - "/v1/customers/ids"
I need a new endpoint that returns Map of customerId->emailId. Since my resource is same I want to call same endpoint "v1/customers/ids"
I want api to be Restful.
I followed this article to create a custom media type - https://www.baeldung.com/spring-rest-custom-media-type
#RequestMapping(value = "/ids",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public List<String> getEmailIdsByCustomerIds(#RequestBody List<String> customerIds) {
return customerService.getEmailIdsByCustomerIds(customerIds);
}
#RequestMapping(value = "/ids",
method = RequestMethod.POST,
produces = "application/custIdToEmailId+json")
#ResponseStatus(HttpStatus.OK)
public Map<String, String> getCustomerIdToEmailIdMapByCustomerIds(#RequestBody List<String> customerIds) {
return customerService.getCustomerIdToEmailIdMapByCustomerIds(customerIds);
}
When I hit this endpoint using Postman I get - 415 Unsupported Media Type exception
#RequestMapping(value = "/ids",
method = RequestMethod.GET,
produces = "application/custIdToEmailId+json")
#ResponseStatus(HttpStatus.OK)
public Map<String, String> getCustomerIdToEmailIdMapByCustomerIds(#RequestBody List<String> customerIds) {
return customerService.getCustomerIdToEmailIdMapByCustomerIds(customerIds);
}
I am not sure.But try using GET for one of the api

Jersey client. MultivaluedMap goes empty

My RESTful client has this method:
public void testGetCateogrywiseData() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
client.addFilter(new LoggingFilter(System.out));
WebResource service = client
.resource("http://localhost:8080/MyApp/rest/publicdata");
#SuppressWarnings("rawtypes")
MultivaluedMap queryParams = new MultivaluedMapImpl();
queryParams.add("latitude", "18.522387");
queryParams.add("longitude", "73.878437");
queryParams.add("categoryID", "2");
service.queryParams(queryParams);
ClientResponse response = service.get(ClientResponse.class);
System.out.println(response.getStatus());
System.out.println("Form response " + response.getEntity(String.class));
}
On the server side the method looks like this:
#Path("publicdata")
#GET
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String getPublicData() throws JSONException {
MultivaluedMap<String, String> valueMap = uriInfo.getQueryParameters();
Long latString = Long.parseLong(valueMap.getFirst("latitude"));
Long lonString = Long.parseLong(valueMap.getFirst("longitude"));
Long categoryId = Long.parseLong(valueMap.getFirst("categoryID"));
// Do necessary stuff and return json string
return null;
}
My problem is the valueMap at the server end is always empty. It never gets the three parameters that I have sent from the client code. What am I missing?
The problem happens on this line:
service.queryParams(queryParams);
It successfully adds the query params, but it does not change the original service, it returns a new one to you. To make it work you need to change to this:
service = service.queryParams(queryParams);

HTTP Status 500 - org.springframework.web.client.HttpClientErrorException: 404 /

I am using RestTemplate, but when i call postFor function i get following exception, Below are the code for showing detail:
Controller
#Controller
#RequestMapping("/data")
public class DataController {
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public ResponseEntity<ManagementResource> postData(#PathVariable("id") String id,#RequestBody Data1 data) {
RSResponse<Data1> response = new RSResponse<Data1>();
response.setStatus(RSResponse.Status.SUCCESS);
response.setData(data);
return new ResponseEntity<ManagementResource>(HttpStatus.CREATED);
}
}
client code:
RestTemplate rt = new RestTemplate();
Data1 d = new Data1();
d.setEmp_id(1);
d.setEmp_name("abc");
d.setEmp_salary(10000);
Map<String, String> vars = new HashMap<String, String>();
vars.put("id", "JS01");
String url = "http://localhost:8090/JSFFaceletsTutorial/data/{id}";
ResponseEntity<Data1> response = rt.postForEntity(url,d,Data1.class,vars);
Data1 data = response.getBody();
please tell if anyone knows it.
Thanks
Does your service need headers? If so, you can pass like this,
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Accept", "application/json");
HttpEntity<Data1> request = new HttpEntity<Data1>(d, headers);
ResponseEntity<Data1> response = rt.postForEntity(url,request,Data1.class,vars);
Data1 data = response.getBody();

begin array but was string GSON

I have a Web Service REST :
#Path("/Vehicles")
public class Vehicles{
#GET
#Path("/Cars")
#Produces(aplicattion/json)
public String Cars() {
Car[] cars = Consulting my database...
Gson gson = new Gson();
return gson.toJson(cars);
}
I consume the web service:
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(
"http://localhost:8080/Concessionaire/rest/Vehicles/Cars");
HttpResponse resp = httpClient.execute(get);
String respGET = EntityUtils.toString(resp.getEntity());
Gson gson = new Gson();
Cars[] c = gson.fromJson(respGET,Cars[].class);
}catch(Exception e){
}
But appears this exception: Expected BEGIN_ARRAY but was String at line 1 colum 6
What is the problem ?
Your method returns a String
public String Cars()
The client code expects a Car array
Cars[] c = gson.fromJson(respGET,Cars[].class);
Gson expects the BEGIN_ARRAY event while parsing the json but instead finds a String. To fix it, send a Cars[] using the jersey Response class and change the return type to Response.
return Response.ok(myCarsArray).build();