I am trying to query a server that looks like this:
Server Code
#RequestMapping(value = "/query_user", method = RequestMethod.GET)
public String queryUser(#RequestParam(value="userId", defaultValue="-1") String userId)
{
int id = Integer.parseInt(userId);
User user = this.service.getUser(id);
...
return userJson;
}
This method works when I test with PostMan
Client Code
private synchronized void callServer(int id)
{
final String URI = "http://localhost:8081/query_user";
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> map = new LinkedMultiValueMap();
map.add("userId", id);
restTemplate.getMessageConverters()
.add(new MappingJackson2HttpMessageConverter());
// Modified to use getForEntity but still this is not working.
ResponseEntity<String> response
= restTemplate.getForEntity(URI, String.class, map);
}
How can I fix this? It is important that I receive the userJson from the Server side.
EDIT
After changing to getForEntity() method I keep getting the defaultValue of -1 on the server side. There must be something else wrong with my code. I am definitly sending a userId that is NOT -1.
Your queryUser() method mapped to GET; from client you call POST restTemplate.postForEntity
I was able to solve it by using a UriComponentsBuilder.
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(URI)
.queryParam("userId", id);
Essentially it is appending the parameter to the URI which is what I believe PostMan is doing (that is how I thought about it).
Reference:
https://www.oodlestechnologies.com/blogs/Learn-To-Make-REST-calls-With-RestTemplate-In-Spring-Boot
Related
For various REST api endpoints, the user_id will reach the backend, needed for further processing and then, sent back as a response to the front end.
I have a feeling I can do this through the header instead of passing it as a path parameter each time, except I can't seem to find the relevant information yet.
At the moment I send the response as a ResponseEntity. I would like, if possible, to keep this option.
I am using Java and Spring Boot.
example based on
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html
edited to add readign header from request
#RequestMapping("/handle")
public ResponseEntity<String> handle(HttpServletRequest httpRequest) {
String userId= httpRequest.getHeader("user_id");
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("user_id", userId);
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
I have decided that the best approach for my scenario, where I only need to fetch the user id and then respond back with it, is to use the #RequestHeader("userId") Long userId annotation.
Let's have a look at how I had configured the enpoint initially:
#PostMapping(path = "/add-follower/{userIdForFollowing}/{currentUserId}")
public ResponseEntity<String> addFollower(#PathVariable ("userIdForFollowing") Long userIdForFollowing, #PathVariable Long currentUserId)
{
Follow newFollow = followService.returnNewFollow(userIdForFollowing, currentUserId);
newFollow = followService.saveFollowToDb(newFollow);
return new ResponseEntity<>("Follow saved successfully", HttpStatus.OK);
}
Now, let's look at how I refactored the endpoint to fetch the id's from the header and return them in the response:
#PostMapping(path = "/add-follower")
public ResponseEntity<String> addFollower(#RequestHeader("userIdForFollowing") Long userIdForFollowing, #RequestHeader("currentUserId") Long currentUserId)
{
Follow newFollow = followService.returnNewFollow(userIdForFollowing, currentUserId);
newFollow = followService.saveFollowToDb(newFollow);
//here I will add more code which should replace the String in the ResponseEntity.
return new ResponseEntity<>("Follow saved successfully", HttpStatus.OK);
}
I'm trying to use RestTemplate to call POST api like that :
RequestorParam test = new RequestorParam();
test.setScopeMcg("MCG");
test.setSituatedDealIds(situatedDealIds);
String url = "http://localhost:" + serverPort + "/retrieveAttributes";
ResponseEntity<SituatedDeals> response = restTemplate.postForEntity(url, test, SituatedDeals.class);
and the code of the controller is like ;
#PostMapping(value = "/retrieveAttributes", produces = "application/json")
#ResponseBody
#Duration
public SituatedDeals retrieveAttributes(
#RequestParam String scopeMcg,
#RequestBody SituatedDealIds situatedDealIds
) {
log.info("success")
}
i'm getting bad request, can someone help ?
According to your controller code, you are actually not returning any Response Entity of type SituatedDeals, just logging it as success. this might be the reason for the null object in response.
The scopeMcg is a RequestParameter so you should be passing it in a request param format i.e http://localhost:8080/retrieveAttributes?scopeMcg=MCG
Reference:Spring Request Param
Your test Object is the actual payload for your post request which should be of type SituatedDealIds object.
Reference: Rest-Template post for Entity
I'm currently developing my first java program who'll make a call to a rest api(jira rest api, to be more especific).
So, if i go to my browser and type the url =
"http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog"
I get a response(json) with all the worklogs of the current user.
But my problem is, how i do my java program to do this ?
Like,connect to this url, get the response and store it in a object ?
I use spring, with someone know how to this with it.
Thx in advance guys.
Im adding, my code here:
RestTemplate restTemplate = new RestTemplate();
String url;
url = http://my-jira-domain/rest/api/latest/search/jql=assignee=currentuser()&fields=worklog
jiraResponse = restTemplate.getForObject(url,JiraWorklogResponse.class);
JiraWorkLogResponse is a simple class with some attributes only.
Edit,
My entire class:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity getWorkLog() {
RestTemplate restTemplate = new RestTemplate();
String url;
JiraProperties jiraProperties = null;
url = "http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog";
ResponseEntity<JiraWorklogResponse> jiraResponse;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders = this.createHeaders();
try {
jiraResponse = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),JiraWorklogResponse.class);
}catch (Exception e){
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return ResponseEntity.status(HttpStatus.OK).body(jiraResponse);
}
private HttpHeaders createHeaders(){
HttpHeaders headers = new HttpHeaders(){
{
set("Authorization", "Basic something");
}
};
return headers;
}
This code is returning :
org.springframework.http.converter.HttpMessageNotWritableException
Anyone knows why ?
All you need is http client. It could be for example RestTemplate (related to spring, easy client) or more advanced and a little more readable for me Retrofit (or your favorite client).
With this client you can execute requests like this to obtain JSON:
RestTemplate coolRestTemplate = new RestTemplate();
String url = "http://host/user/";
ResponseEntity<String> response
= restTemplate.getForEntity(userResourceUrl + "/userId", String.class);
Generally recommened way to map beetwen JSON and objects/collections in Java is Jackson/Gson libraries. Instead them for quickly check you can:
Define POJO object:
public class User implements Serializable {
private String name;
private String surname;
// standard getters and setters
}
Use getForObject() method of RestTemplate.
User user = restTemplate.getForObject(userResourceUrl + "/userId", User.class);
To get basic knowledge about working with RestTemplate and Jackson , I recommend you, really great articles from baeldung:
http://www.baeldung.com/rest-template
http://www.baeldung.com/jackson-object-mapper-tutorial
Since you are using Spring you can take a look at RestTemplate of spring-web project.
A simple rest call using the RestTemplate can be:
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
The issue could be because of the serialization. Define a proper Model with fields coming to the response. That should solve your problem.
May not be a better option for a newbie, but I felt spring-cloud-feign has helped me to keep the code clean.
Basically, you will be having an interface for invoking the JIRA api.
#FeignClient("http://my-jira-domain/")
public interface JiraClient {
#RequestMapping(value = "rest/api/latest/search?jql=assignee=currentuser()&fields=", method = GET)
JiraWorklogResponse search();
}
And in your controller, you just have to inject the JiraClient and invoke the method
jiraClient.search();
And it also provides easy way to pass the headers.
i'm back and with a solution (:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<JiraWorklogIssue> getWorkLog(#RequestParam(name = "username") String username) {
String theUrl = "http://my-jira-domain/rest/api/latest/search?jql=assignee="+username+"&fields=worklog";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JiraWorklogIssue> response = null;
try {
HttpHeaders headers = createHttpHeaders();
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
}
catch (Exception eek) {
System.out.println("** Exception: "+ eek.getMessage());
}
return response;
}
private HttpHeaders createHttpHeaders()
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic encoded64 username:password");
return headers;
}
}
The code above works, but can someone explain to me these two lines ?
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
And, this is a good code ?
thx (:
I am trying to consume the following HTTPS endpoints from Yahoo Weather Service:
Yahoo Weather Service API
I am doing some special query according to the API to get the current weather at some parametrized location.
#Service("weatherConditionService")
public class WeatherConditionServiceImpl implements WeatherConditionService {
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public WeatherCondition getCurrentWeatherConditionsFor(Location location) {
RestTemplate restTemplate = new RestTemplate();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(URL);
stringBuilder.append("?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22");
// TODO: Validate YQL query injection
stringBuilder.append(location.getName());
stringBuilder.append("%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
WeatherQuery weatherQuery = restTemplate.getForObject(stringBuilder.toString(), WeatherQuery.class);
// TODO: Test Json mapping response
Condition condition = weatherQuery.getQuery().getResults().getChannel().getItem().getCondition();
return new WeatherCondition(condition.getDate(), Integer.parseInt(condition.getTemp()), condition.getText());
}
Location is a class that provides the attribute "name" that is a String description of the location, such as "New York" or "Manila".
Condition an other classes just map the returning object.
When executing I get the following HTTP response:
org.springframework.web.client.HttpClientErrorException: 403 Forbidden
So this means I am not authorized to access the resource from what I understand.
The URL works great if I just copy & paste it in a web browser:
Yahoo Weather Query
I think that mapping is not a problem since I am not getting "400" (Bad Request) but "403" (Forbidden)
There must be some error on the way I use the RestTemplate object. I am researching but I can't find an answer.
The docs say you need an api key. But when I make a call like this:
fetch('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
.then(resp=> resp.json())
.then((res)=>console.log(res.query.results))
https://repl.it/NeoM
It works fine without one. Perhaps you've been blackisted for hitting the api too often.
Your code seems fine.
I finally found the answer. It finally WAS a Bad Request because I needed to pass the parameters differently (not as part of the URL).
I found the answer here. Here goes the code for my particular Yahoo Weather API call return a String (I still will have to do some work to use the mapping).
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public String callYahooWeatherApi() {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(URL)
.queryParam("q", "select wind from weather.forecast where woeid=2460286")
.queryParam("format", "json");
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.build().encode().toUri(),
HttpMethod.GET,
entity,
String.class);
return response.getBody();
}
We're using Spring rest api.
We have some endpoint which can be called with SOME query params.
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<SomeObject>> someMethod(#RequestParam(required = false) MultiValueMap<String, String> params)
And we don't know in advance which params it will receive.
So we're using MultiValueMap and then just handle it.
But in the response we should return String which represents this endpoint with all the parameters.
For example, if a client calls it as
/someendpoint?param1=value1¶ms2=value2¶ms3=[value3a,value3b]
we just need to return this string.
Of cause we can construct this string iterating through the map.
But I think spring has a more elegant way.
You can try the following.
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<SomeObject>> someMethod(HttpServletRequest request, #RequestParam(required = false) MultiValueMap<String, String> params) {
String url = request.getRequestURL().toString() + (request.getQueryString() == null ? "" : "?" + request.getQueryString());
}
Take a look at Spring HATEOAS ControllerLinkBuilder.
Maybe you could use it generate URLs from the given parameters. Havent tried it though.
List<Order> methodLinkBuilder = methodOn(YourController.class).someMethod(params);
Link selfLink = linkTo(methodLinkBuilder).withRel("self");