Easy way to access webservices with GET queries? - java

I'm trying to create a small Java client that can call a GET webservice with a query. Imagine a gas/fuel webservice like this:
http://mywebservice.com/search.xml?lat=50.5&lng=30.33&fuels=Diesel&radius=2
Ideally I'd have a website where the user can enter information like location, fuel, radius in km and so on.
What technology could I best use to make the webservice calls simpler?
At the moment I'm constructing the query manually like this:
stringbuilder.append("http://mywebservice.com/search.xml?lat=")
.append(latField.getText())
.append("&lng=")
.append(lngField.getText())
.append("&fuels=")
.append(fuelsField.getText())
.append("&radius=")
.append(radiusField.getText());
You get the idea.
I'm questioning: is there anything smarter to call webservice queries? How are you doing this? How could this be improved?

You can use JAX-RS to build/deploy/invoke this REST endpoint easily.
The client may look like:
Client client = ClientBuilder.newClient();
WebTarget target = client.target(".../gas");
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<>();
map.add("lat", "50.5");
map.add("lng", "30.33");
map.add("fuels", "Diesel");
map.add("radius", "2");
target.request().post(Entity.form(map));
A similar client code is at:
https://github.com/arun-gupta/javaee7-samples/blob/master/jaxrs/jaxrs-client/src/main/java/org/javaee7/jaxrs/client/TestJAXRS2Client.java
The endpoint may look like:
#Path("/gas")
public class GasService {
#POST
public String post(#FormParam("lat")String lat, #FormParam("lng")String lng) {
// search based upon lat, lng, etc
}
}
A complete endpoint definition is at:
https://github.com/arun-gupta/javaee7-samples/blob/master/jaxrs/jaxrs-client/src/main/java/org/javaee7/jaxrs/client/MyResource.java

A well known library is:
http://hc.apache.org/httpcomponents-client-4.3.x
It is very simple and flexible.
For your usecase you could do something like:
URI uri = new URIBuilder()
.setScheme("http")
.setHost("www.google.com")
.setPath("/search")
.setParameter("q", "httpclient")
.setParameter("btnG", "Google Search")
.setParameter("aq", "f")
.setParameter("oq", "")
.build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
For the full example and more:
http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/fundamentals.html#d5e49

I like spring a lot, so I could recommend you rest template :
http://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
The example given is :
Map<String, String> vars = new HashMap<String, String>();
vars.put("hotel", "42");
vars.put("booking", "21");
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);
To match your question, that could become :
Map<String, String> vars = new HashMap<String, String>();
vars.put("lat", latField.getText());
vars.put("lng", lngField.getText());
vars.put("fuels", fuelsField.getText());
vars.put("radius", radiusField.getText());
String result = restTemplate.getForObject("http://mywebservice.com/search.xml?lat={lat}&lng={lng}&fuels={fuels}&radius={radius}", String.class, vars);

You can write a webservice client using standard frameworks, depending on the type of webservice. For example, Axis2 for SOAP based or Jersey for REST based.

Finally I ended up using org.apache.cxf.jaxrs.client.WebClient as follows:
WebClient.create("http://mywebservice.com/search.xml")
.query("lat", 50.5)
.query("lng", 30.33)
.query("fuels", "Diesel")
.query("radius", 2)
.get(Search.class);

Related

Coinbase pagination returning {"errors":[{"id":"not_found","message":"Not found"}]}

I am trying to iterate over a paginated list of accounts but when I send a request using the value from "next_uri" I receive an error from the server:
{"errors":[{"id":"not_found","message":"Not found"}]}
I am correctly adding headers etc as all other API calls work fine, its just the request using the "next_uri" that is not working. I think I am following the api spec correctly so I am unsure what is the issue and how to fix it. Does anyone know what is wrong with the code / logic please?
Simplified code:
ArrayList<X> results = new ArrayList<>();
String uri = "/v2/accounts";
javax.ws.rs.client.Client client = getClient();
while(uri != null){
T response = client.target("https://api.coinbase.com")
.path(uri).request(MediaType.APPLICATION_JSON).get(responseType);
results.addAll(response.getData());
uri = response.getPagination()==null ? null :response.getPagination().getNextUri();
}
return results;
The results are this:
Request 1:
https://api.coinbase.com/v2/accounts
Response 1: pagination":
{"ending_before":null,"starting_after":null,"previous_ending_before":null,"next_starting_after":"ef35df6c-a45b-5858-b755-f12a709cf26e","limit":25,"order":"desc","previous_uri":null,"next_uri":"/v2/accounts?starting_after=ef35df6c-a45b-5858-b755-f12a709cf26e"},"data":[{....}]
Request 2:
https://api.coinbase.com/v2/accounts%3Fstarting_after=ef35df6c-a45b-5858-b755-f12a709cf26e
Response 2:
{"errors":[{"id":"not_found","message":"Not found"}]}
This was related to how the jax-rs library needs the query params adding. Just relying on the uri is not enough, the parameters also need adding specifically:
target = target.queryParam(e.getKey(), e.getValue());
so the final code is something like
WebTarget target = client.target(e"https://api.coinbase.com");
if(params !=null){
for(Map.Entry<String, String> e : params.entrySet()){
target = target.queryParam(e.getKey(), e.getValue());
}
}
target = target.path(path);
return target.request(MediaType.APPLICATION_JSON).get(responseType);

how to get the value from HttpMethodParams

At client side I use the following code:
HashMap<String, String> paramMap = new HashMap<>();
paramMap.put("userId", "1579533296");
paramMap.put("identity", "352225199101195515");
paramMap.put("phoneNum", "15959177178");
HttpClient client = new HttpClient();
PostMethod method = new PostMethod("http://localhost:8088/requestTest");
HttpMethodParams p = new HttpMethodParams();
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
p.setParameter(entry.getKey(), entry.getValue());
}
method.setParams(p);
client.executeMethod(method);
And the code of my server-side is like this:
#RequestMapping("/requestTest")
public void requestTest(HttpServletRequest request) throws IOException {
String userId = request.getParameter("userId");
String identity= request.getParameter("identity");
String phoneNum= request.getParameter("phoneNum");
System.out.println(userId+identity+phoneNum);
}
but I got the null value of userId,identity,and phoneNum,so how can I get the value of them? I know I can use method.setParameter(key,value) to set the parameter at client-side and use getParameter(key) to get the parameter value, but I just curious if there any way to get the value at server-side set by HttpMethodParams.
I think , you are getting confused between user defined parameters set in HttpServletRequest and HttpMethodParams .
As per JavaDoc of - HttpMethodParams ,
This class represents a collection of HTTP protocol parameters
applicable to HTTP methods.
These are predefined parameters specific to that HTTP method (see this)and has nothing to do with - HttpServletRequest parameters.
Request parameters need to be set as illustrated here
You have to also note that all these classes (HttpClient, PostMethod, HttpMethodParams etc ) that you are using on client side are from Apache to just be a convenient way to generate and call a HTTP end point but eventually what you will have on server side is a HttpServletRequest and there system is not Apache HttpClient specific.
So all you got on server side is to extract a named header or headers using - getHeaders() , getIntHeader() , getHeaderNames() , getDateHeader() , getProtocol() etc . Server side is standardized so you shouldn't see anything like - HttpMethodParams there.
You have to send your parameters using HttpServletRequest.
HttpMethodParams represent a collection of HTTP protocol parameters applicable to HTTP methods. List of Http method parameter can be found here.
But if you want to send it forcibly by HttpMethodParams you can set the JSON representation of your parameter in one of the variables of HttpMethodParameter and retrieve its value using that variable name.
Sample Code:
HttpMethodParams p = new HttpMethodParams();
p.setCredentialCharset("{userId":1579533296}");
//for loop not required
//your code
Now you can parse that JSON using ObjectMapper and get your required value.
Sample Code:
HttpMethodParams p = new HttpMethodParams();
JSONObject jsonObj = new JSONObject(p.getCredentialCharset());
jsonObj.get("userdId");
Note: This may work but not the recommended way.

Spring RestTemplate: sending array / list of String in GET request

I'm trying to send a array / list of String to my REST server through Spring RestTemplate.
This is on my android side:
private List<String> articleids = new ArrayList<>();
articleids.add("563e5aeb0eab252dd4368ab7");
articleids.add("563f2dbd9bb0152bb0ea058e");
final String url = "https://10.0.3.2:5000/getsubscribedarticles";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("articleids", articleids);
java.net.URI builtUrl = builder.build().encode().toUri();
Log.e("builtUrl", builtUrl.toString());
The builtUrl is: https://10.0.3.2:5000/getsubscribedarticles?articleids=%5B563e5aeb0eab252dd4368ab7,%20563f2dbd9bb0152bb0ea058e%5D
On the server side:
#RequestMapping(value = "/getsubscribedarticles", method = RequestMethod.GET)
public List<Posts> getSubscribedPostFeed(#RequestParam("articleids") List<String> articleids){
for (String articleid : articleids {
logger.info(" articleid : " + articleid);
}
}
The server logs:
.13:11:35.370 [http-nio-8443-exec-5] INFO c.f.s.i.ServiceGatewayImpl
- articleid : [563e5aeb0eab252dd4368ab7
.13:11:35.370 [http-nio-8443-exec-5] INFO c.f.s.i.ServiceGatewayImpl
- articleid : 563f2dbd9bb0152bb0ea058e]
Which I can see is wrong as the list should not have a '[' on the first item and a ']' on the last item.
I have read this thread How to pass List or String array to getForObject with Spring RestTemplate but it does not actually answer the question.
The selected answer issues out a POST request, but I want to do a GET request , also it requires an additional object to work to hold the list and I would prefer to not create extra objects if I can do it with Spring RestTemplate natively.
Using Java 8, this worked for me :
UriComponentsBuilder builder = fromHttpUrl(url);
builder.queryParam("articleids", String.join(",", articleids));
URI uri = builder.build().encode().toUri();
It forms the URL like:
https://10.0.3.2:5000/getsubscribedarticles?articleids=123,456,789
I would expect that the correct working url is something like:
https://10.0.3.2:5000/getsubscribedarticles?articleids[]=123&articleids[]=456&articleids[]=789
After a quick look at the code of public UriComponentsBuilder queryParam(String name, Object... values), I would solve it by using UriComponentsBuilder this way:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("articleids[]", articleids.toArray(new String[0]));
It is important that, the second parameter is an array but not an Object/Collection!
You did everything correct. You just need to call it without the [].
Just invoke it with .../getsubscribedarticles/articleids=foo,bar,42
I tested this with Spring Boot 1.2.6 and it works like this.
Thanks to dOx for his suggestion - I managed to solve this with the PathVariable - i set the list in my url for android:
final String url = "https://10.0.3.2:5000/getsubscribedarticles/"+new ArrayList<>(articleids);
For my rest server:
#RequestMapping(value = "/getsubscribedarticles/[{articleids}]", method = RequestMethod.GET)
public List<Posts> getSubscribedPostFeed(#PathVariable String[] articleids){
}

java rest client for mixed parameter forms

I have a rest method which takes two parameters one map parameter, and the other is a String variable
#POST
public returnValue postMethod( Map<String,String> anotherMap,
#QueryParam("name") String name
) {}
It is easy to pass each parameter by itself where
the map parameter can be passed using XML as follow :
ClientResponse response = service
.type(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML)
.post(ClientResponse.class, map).getEntity(ClientResponse.class).
and the QueryParam can be passed as usual :
service.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.post(ClientResponse.class, f)
where f is a Form ,
the question is : how can we pass both parameter together from the same Java client ?
So you're asking - how do I POST a Map and pass a String as a query param? With sending and receiving XML.
Here's how I'd do it:
ClientBuilder clientBuilder = ClientBuilder.newBuilder();
//Do some building code
Client client = clientBuilder.build();
WebTarget target = client.target(endPoint);
Response response = target
.queryParam("name", "value")
.request(MediaType.APPLICATION_XML_TYPE)
.post(Entity.entity(map), MediaType.APPLICATION_XML_TYPE);
Hope this helps.

How to get STRING response from RestTemplate postForLocation?

I'm creating a REST Client in Java with RestTemplate from Spring Framework.
Everything is fine until i have to do a post with postForLocation.
The webservice i'm having access return a json with informations about the POST ACTION.
In PHP it's fine but i really don't understand how to do in Java with RestTemplate.
public String doLogin()
{
Map<String, String> args = new HashMap<String, String>();
args.put("email", AUTH_USER);
args.put("token", AUTH_PASS);
String result = restTemplate.postForLocation(API_URL + "account/authenticate/?email={email}&token={token}", String.class, args);
return result;
}
This returns NULL.
With same code but using getForObject (and of course, changing the URL to something right) I have a full response, i.e. this works:
String result = restTemplate.getForObject(url, String.class);
So... how get the RESPONSE from a postForLocation?
Obs.: Sorry if this question is dumb. I'm beginner in Java
The postForLocation method returns the value for the Location header. You should use postForObject with the String class, which returns the server's response.
So like this:
String result = restTemplate.postForObject(API_URL + "account/authenticate/?email={email}&token={token}", String.class, args);
This will return the response as a string.
Thanks to one of answers i've figured out how get the response from a POST with Spring by using the postForObject
String result = restTemplate.postForObject(API_URL + "account/authenticate/?email="+ AUTH_USER +"&token="+ AUTH_PASS, null, String.class);
For some reason i can't use arguments with MAP and have to put them inline in URL. But that's fine for me.

Categories

Resources