call external api in spring boot - spring-boot

I am using get api for getting data from url but it give response in string format i want exact response or json response
`
#RestController
public class HelloController {
#GetMapping("/discover")
private String getApi(){
String url ="https://discover.search.hereapi.com/v1/discover?at=18.49093,73.8332&limit=2&q=restaurant&in=countryCode:IND&apiKey=hhV0nHGeHgrg5LACzw7dDJNe49bYCNvkCWxV94LlHno";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(url,String.class);
//Object[] result = restTemplate.getForObject(url, Object[].class);
//List<String> arr = new ArrayList<String>();
//arr.add(restTemplate.getForObject(url,String.class));
return result;
}
}
`

In this case, you get what you ask for, which is a String. If the string being returned is JSON, you can either use an ObjectMapper to deserialize it into an object that represents the response or have RestTemplate do it for you.
Assuming the response payload looks like this:
{
"name": "some name"
}
Then you'd create a class to represent the response (using lombok for getters and setters):
#Getter
#Setter
public class ApiResponse {
private String name;
}
Then you can either let RestTemplate do the work for you:
ApiResponse result = restTemplate.getForObject(url, ApiResponse.class);
Or, handle it yourself
String result = restTemplate.getForObject(url,String.class);
ApiResponse apiResponse = new ObjectMapper().readerFor(ApiResponse.class).readValue(result);

Related

Spring boot: Sending a JSON to a post request that uses a model as a param

Lets say I have a predefined post mapping as such:
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}
and the valDetail object as follows:
#Data
#Component
#Entity
#Table(name = "val_portal")
public class valDetail {
#Id
#Column(name = "valcode")
private String valCode;
#Column(name = "valname")
private String valName;
}
How would I go about actually sending JSON values from a separate service to this /add endpoint so that they are properly received as a valDetail object?
Currently I tried this implementation but I keep getting a 415 response code.
JSONObject valDetail = new JSONObject();
valDetail.put("valCode",request.getAppCode().toLowerCase());
valDetail.put("valName", request.getProjectName());
String accessToken = this.jwtUtility.retrieveToken().get("access_token").toString();
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setBearerAuth(accessToken);
authHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(valDetail.toString(), authHeaders);
ResponseEntity<String> loginResponse = restTemplate.exchange(uri,
HttpMethod.POST,
entity,
String.class);
If you want to pass data as json you don't want to take Model try to use #ResponseBody annotation to transfer data through json.
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}

Creat a JSONObject : Spring boot

I would like to create a JSONObject :
#RequestMapping(value = "/test", method = RequestMethod.GET)
#ResponseBody
public JSONObject Test() {
JSONObject test = new JSONObject();
test.put("name","caroline");
return test;
}
it's giving me as a result :
{"map":{"name":"caroline"}}
But I was waiting for something like that :
{"name":"caroline"}
I don't know where is it the problem , I just followed this exemple
I tried with your code with a sample spring boot project and I get the error,
No converter for [class org.json.JSONObject]
The reason for this error is explained clearly here. To reiterate the answer, JSONObject classes don't have getters and hence the error. By default spring-boot starter web dependency has Jackson web support which can convert any POJO class to JSON object. So as the answer by #süleyman-can using a POJO is the right way to handle this.
In case, you can't use a POJO class because the fields in the response will be different for each request. For example, you have to send
{"a": "b"}
for one response and
{"c": "d"}
for another response, you can always use Map<String, String> like this,
#RequestMapping(value = "/test", method = RequestMethod.GET)
#ResponseBody
public Map<String, String> test() {
Map<String, String> test = new HashMap<>();
test.put("name","caroline");
return test;
}
and the response would come like this,
{"name":"caroline"}
I hope you are talking about org.json package
If you really want to use JSONObject to create your JSON, then the following code works. It's just that you can change the return type from JSONObject to String.
#RequestMapping(value = "/test", method = RequestMethod.GET)
#ResponseBody
public String Test() {
JSONObject test = new JSONObject();
test.put("name","caroline");
return test.toString();
}
you can try this
1- add this dependecy in pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
2- i have this class for example
public class Car {
private String color;
private String type;
// standard getters setters
}
2- Java Object to JSON
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
objectMapper.writeValue(new File("target/car.json"), car);
must result like it:
{"color":"yellow","type":"renault"}
3- JSON to Java Object
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);
You can do by creating a Class
class MyResponseClass {
private String name;
public MyResponseClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Initial:
#RestController
class MyController {
#GetMapping("/test")
public MyResponseClass getMyResponseClass() {
final MyResponseClass test = new MyResponseClass("caroline");
return test;
}
}
I suggest you read this article: Building an Application with Spring Boot

Values in the response of api are empty

ResponseInJsonFormat is a class,
#Builder
#Getter
public class ResponseInJsonFormat {
// Id field in Eloqua
private String id;
// List of field values
private List<FieldValues> fieldValues;
}
And FieldValues is also a class defined as,
#Builder
#Setter
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class FieldValues {
// id of the parameter
private String ID;
// parameters
private String type;
// Value :- value of the parameter
private String value;
}
I'm writing an api ,
#RequestMapping(value = "/service/XYZService", method = RequestMethod.POST)
public ResponseInJsonFormat sendData(#RequestParam String a) {
FieldValues parameter = FieldValues.builder()
.ID(FIELD_ID)
.type(FILED_TYPE)
.value(a)
.build();
List<FieldValues> values = Arrays.asList(parameter);
ResponseInJsonFormat response = ResponseInJsonFormat .builder()
.fieldValues(values)
.id(ID)
.build();
// need to return ResponseInJsonFormat
return response
}
But when I call to a service it returns something like,
{
"id": "110",
"fieldValues": [
{}
]
}
Could somebody assist about this empty json object of fieldValues.
I havnt understand why to put #JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
if I dont use this annotation I get an error as,
no properties discovered to create BeanSerializer
So I used the annotation, the error has gone but getting empty value for the same, even though the value is explicitly assigned.
I do not understand why to do all this it just being a list.
Is there any document I should read about,please advice.
If I'm not wrong, spring return the response in JSON format. Then why to do all this.

Spring #RequestMapping method without #RequestBody

In a Spring Boot Controller method, how do I get the body of a POST? All of the examples I have seen use #RequestBody. How do I get the body without using #RequestBody?
I am writing a method to handle Slack Events. When Slack POSTs an event, the body is in JSON and often contains a "user" key. Depending on the type of event, the value of "user" can either be a string or an object. Because of this, I cannot create a single Class and write
#RequestMapping(path = "/slackRequest", method = RequestMethod.POST)
public String handleSlackRequest(#RequestBody final SlackRequest slackRequest)
Answer: Implementing the approach suggested by #ChiDov, the solution is to keep the #RequestBody, import
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
define the user field (and a new field to store the 'user' if it is a simple String value) as
#OneToOne
private SlackEventUser user;
private String slackUserId;
and define its Setter method as
#JsonSetter("user")
public void setUser(JsonNode userNode) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
if (userNode.isObject()) {
SlackEventUser slackEventUser = mapper.convertValue(userNode, SlackEventUser.class);
this.user = slackEventUser;
} else {
String userString = mapper.convertValue(userNode, String.class);
this.slackUserId = userString;
this.user = null;
}
}
Updated: I would make your DTO like :
Class SlackRequest{
...
private String eventType;
private JsonNode user;
...
public String getUser(){
return user.asText();
}
}
and in controller:
#RequestMapping(path = "/slackRequest", method = RequestMethod.POST)
public String handleSlackRequest(#RequestBody final SlackRequest slackRequest){
if(slackRequest.getEventType == "objectEvent"){
SomeObject user = mapper.convertValue(slackRequest.getUser(), SomeObject.class);
// do something with the object
}else{
// do something with the user string
}
}
Get Inspiration from : How to deserialize dynamic field using Jackson?

Spring Service and RestTemplate Client always Unexpected end of file from server

My POJO:
public class Product {
String name;
int price;
public Product(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
My Controller:
#RestController
#RequestMapping("/rest")
public class RstController {
#RequestMapping(value = "/getProductPost2", method=RequestMethod.POST, produces = {"application/json"})
public Product getProductPost2(#RequestBody Product p){
System.out.println(p.getName());
return p;
}
My Client, using JUnit(I've tried all the lines commented, the same error everytime):
public class RestTemplatePostTest {
#Test
public void testee(){
String url = "http://localhost:8443/ShoppingCartSpringMVCSpringDataHibernate/rest/getProductPost2";
Product p = new Product();
p.setName("produs");
p.setPrice(22);
String json = "{\"name\":\"pen\",\"price\":10}";
HttpEntity<Product> request = new HttpEntity<Product>(p);
RestTemplate rt = new RestTemplate();
rt.postForObject(url, json, String.class);
//rt.postForObject(url, p, String.class);
//rt.exchange(url, HttpMethod.POST, request, Product.class);
//rt.exchange(url, HttpMethod.POST, request, String.class);
//assertEquals("produs",p2.getName());
}
}
When I'm using POSTMAN, it works.
I haven't found any other option on the internet and it's been 2 days since I'm trying to do this . Any opinion or tutorial is more than welcomed.
Edit1: Also, a simple GET also doesn't work,but it works in browser or in POSTMAN.
#RequestMapping(value = "/getProductGet", method=RequestMethod.GET)
public String getProductGet{
return "hello World!!";
}
#Test
public void testGet(){
String url = "http://localhost:8443/ShoppingCartSpringMVCSpringDataHibernate/rest/getProductGet";
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response= rt.getForEntity(url, String.class);
}
When in debug mode, it stops in my breakpoint when called by browser or POSTMAN, but it doesn't get there when using rest template.
Perhaps something to do with the fact that I'm using Spring security?
I think the problem is that your request has a wrong data type which server can not parse and thus can not reply.
Since you are sending a POST request with JSON Content-Type, your Product must be JSON-encoded.
To do that, you need to add a json converter so modify your code to some thing like this:
RestTemplate rt= new RestTemplate();
rt.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Product recievedProduct = rt.postForObject(url, p, Product.class);
Don't forget to add the jackson dependency.

Resources