I am kind of new to RESTful web services and need some help. I have service which will return a list of products. The URL looks like the following:
/example/product/6666,6667?expand=sellers&storeIds=2,1
To define this service I have this interface:
#Path("/example")
public interface Service {
#GET
#Path("/products/{pIds}")
#Produces( "application/json" )
public ServiceResponse<ProductsList> getProducts(
#PathParam("pIds") String productsIds,
#QueryParam("expand") String expand,
#QueryParam("storeIds") String storeIds) throws Exception;
}
I am assuming here that I am getting the productsIds as a string and that I will need to manually split this string into a list of ids, with delimiter as a comma.
Is there a way to instead get the parameters as list, instead of doing manually it from my side? Or is there a library that I can use to do this in an automated way?
Thanks
You can deserialize the product id's directly into a list with some minor change to your service definition. Try this instead:
#Path("/example")
public interface Service {
#GET
#Path("/products/{pIds}")
#Produces( "application/json" )
public ServiceResponse<ProductsList> getProducts(
#PathParam("pIds") List<String> productsIds,
#QueryParam("expand") String expand,
#QueryParam("storeIds") String storeIds) throws Exception;
}
Change String productsIds to List<String> productsIds.
On a side note, I would recommend passing in the product id's as a query parameter. Your URI should identify a unique resource (in this case products) and it should be stateless.
Related
I am using spring to build a REST api with PageAble, to get numberofPages,itens...
first, i did a mapping like this
public ResponseEntity<Data> findByName(#PathVariable(value="name",required=true) String name, #RequestParam(value="page", defaultValue="0") Integer page, #RequestParam(value="qtd", defaultValue="10") Integer linesPerPage, #RequestParam(value="sort", defaultValue="nome") String sort, #RequestParam(value="direction", defaultValue="ASC") String direction)
So in my url i get for example "url?name=erick&direction=asc" but i need to change to "url?name=erick!asc"
How can i change it?
You can do this. Look at page 3 of https://www.ietf.org/rfc/rfc1738.txt
In you case,you should use #RequestParam("name") instead of #PathVariable.Then the request url will be like "url?name=erick&direction=asc"
Spring has three kinds of Annotation.
#PathVariable
This annotation means the variable is on the url.For example:
#RequestMapping("/{id}")
public void pathVariable(#PathVariable("id") Long id){}
The variable was put between the brace at the url.
#RequestParam
This annotation means the variable is part of the quest param,the request url looks like
stackoverflow.com?name=hhhh
For example:
#RequestMapping("/")
public void requestParam(#RequestParam("id")Long id){}
#RequestBody
This annotation means you will receive some data from request body.And some kind of converter,like jackson,will convert it into a properly object.For example:
#PostMapping("/")
public void requestBody(#RequestBody Example example){}
Okay so I am using a payment service called Thrive cart, I am doing this for a membership website I'm creating. When the user has paid I want them to be redirected to a URL where I can use that data to update the current users information.
The data that get's sent in the params is insane:
http://localhost:5000/user/welcome?thrivecart%5Baccount_id%5D=3196&thrivecart%5Baccount_name%5D=testacount&thrivecart%5Bcustomer%5D%5Bemail%5D=testname8%40gmail.com&thrivecart%5Bcustomer%5D%5Baddress%5D%5Bcountry%5D=GB&thrivecart%5Bcustomer%5D%5Baddress%5D%5Bzip%5D=pe303wu&thrivecart%5Border%5D%5B0%5D%5Bt%5D=product&thrivecart%5Border%5D%5B0%5D%5Bid%5D=6&thrivecart%5Border%5D%5B0%5D%5Bn%5D=Monthly+membership&thrivecart%5Border%5D%5B0%5D%5Bp%5D=799&thrivecart%5Border%5D%5B0%5D%5Bq%5D=1&thrivecart%5Border%5D%5B0%5D%5Bpo%5D=60120&thrivecart%5Border%5D%5B1%5D%5Bt%5D=product&thrivecart%5Border%5D%5B1%5D%5Bid%5D=6&thrivecart%5Border%5D%5B1%5D%5Bn%5D=Monthly+membership&thrivecart%5Border%5D%5B1%5D%5Bp%5D=799&thrivecart%5Border%5D%5B1%5D%5Bq%5D=1&thrivecart%5Border%5D%5B1%5D%5Bpo%5D=60120&thrivecart%5Border_currency%5D=GBP&thrivecart%5Border_id%5D=1041278&thrivecart%5Border_tax%5D=0.2&thrivecart%5Border_tax_id%5D=gb&thrivecart%5Border_total%5D=799&thrivecart%5Bpayment_processor%5D=paypal&thrivecart%5Bproduct_id%5D=6&thrivecart%5Bpurchases%5D%5B0%5D=6&thrivecart%5Bpurchases%5D%5B1%5D=6&thrivecart_hash=a5b711d2288b4cb587511811bc0a3473
So far I've set up a simple controller which doesn't get hit:
#RestController
#RequestMapping("/user")
public class UserController {
#RequestMapping(value = "/welcome", method = RequestMethod.POST)
public void welcomeMember(#PathVariable String data) {
System.out.println(data);
}
}
How do I deal with crazy data like this? Do I have to specific each path param?
First of all, what you seem to get are not path elements but request parameters, so you will need #RequestParam annotations to get the values.
Since there are so many request parameters, I would also recommend to take just one parameter, a Map<String, String>. That Map will contain all the parameters as key/value pairs, for example:
key: "thrivecart[account_id]"
value: "3196"
If you're not sure whether you receive a POST or a GET request, you can also add a second parameter to receive the HttpMethod.
Change your RestController to:
#RestController
#RequestMapping("/user")
public class UserController {
#RequestMapping(value = "/welcome")
public void welcomeMember(#RequestParam Map<String, String> data, HttpMethod method) {
System.out.println(method);
System.out.println(data);
}
}
That looks like a problem with how the rest api is called from the service consumer side.
try sending the data in a request body rather then as a param. This way you can use a POJO to handle the data.
Question 1: So far I've set up a simple controller which doesn't get hit:
As per your URL http://localhost:5000/user/welcome "user" seems to be your projects context name. Try removing #RequestMapping("/user") from your class.
Also, instead of#PathVariable String data use #RequestParam Map<String,String> params. #PathVariable String data is used when data is part of url but in your case it's parameter. Final code should be like below.
#RestController
public class UserController {
#RequestMapping(value = "/welcome", method = RequestMethod.POST)
public void welcomeMember(#RequestParam Map<String,String> params ) {
for(Map.Entry<String, String> entry : params.entrySet()){
//This will print all paramters name and their value
System.out.println(entry.getKey() + "-" + entry.getValue());
}
}
}
Question 2: How do I deal with crazy data like this? Do I have to specific each path param?
I will suggest to follow standard practice. Send data in json format. There are different ways for this depend upon front end technology you are using. One way is Link
My client would send a request corresponding to:
GET http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate?nbPax=&typo=&card
I do this:
#Path("/service/rs") public class MyServiceImpl {
public MyServiceImpl() {
super();
}
#GET
#Path("/{origin}/{destination}/{goDate}/{returnDate}")
public Response getCalendar(#PathParam("origin") String origin, #PathParam("destination") String destination, #PathParam("goDate") String goDate, #PathParam("returnDate") String returnDate, #QueryParam("nbPax") String nbPax, #QueryParam("typo") String typo, #QueryParam("card") String card) {
//print my parameters
return Response.ok("Success").build();
}
}
there cannot map my query parameter, fails with 404, why ?
You need to correct the signature of your method and add the placeholders inside the #Path annotation to map the path parts to those #PathParam-annotated arguments. The parts that are query params should use the #QueryParam annotation.
#GET
#Path("/calendar/{origin}/{destination}/{outwardDate}/{returnDate}")
public Response getInfo(#PathParam("origin") String origin,
#PathParam("destination") String destination,
#PathParam("outwardDate") String outwardDate,
#PathParam("returnDate") String returnDate,
#QueryParam("nbPax") String nbPax,
#QueryParam("typo") String typo,
#QueryParam("card") String card) {
Also, be aware that if you web application is rooted at some context path (this is typical for applications deployed inside Servlet containers like Tomcat or JBoss), the context path will be part of the URL, e.g.
http://[server host]/[app context path]/[class' #Path]/[method's #Path]
This is the address
http://example.com/services/rs/calendar/
and you are calling
http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate
where you are treating word "origin" (and the rest) as parameter, while its actually part of address, I believe you have no REST service attached to:
http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate
Thats why you are getting 404.
Those words you are trying to pull are of type #PathParam, #QueryParam is what you have after ? sign
I have created simple rest service #GET and takes 2 parameters username and password.
I m trying to search how to pass parameters through rest service client and how to get it using the method. I am unable to get the exact answer I want.
How can I pass parameters and how to use that in my webservice?
I don't know what framework you are using but if you use Spring, you can do it like this:
#Controller
public class SampleController {
#RequestMapping(value="/test/{name}/{password}", method = RequestMethod.GET)
public String doTest(#PathVariable String name,#PathVariable String password, ModelMap model) {
System.out.println("REST paras name:"+name+",password:"+password);
return "samplePage";
}
}
then ,url path like [/test/{name}/info] [/test/{name}/info.*] [/test/{name}/info/]
will pass to this method!
You should look on something like:
#HeaderParam or #PathParam
in Jersey it looks like:
#Get
#Path("/mywebservice")
public Response myWebService(#HeaderParam String username,
#HeaderParam String password)
{
...
}
but you should remember that this way of sending/receiving username and password isn't too secure ;)
How can I easily separate JSON values that are sent in the same request?
Given that I POST a JSON to my server:
{"first":"A","second":"B"}
If I implement the following method in the Controller:
#RequestMapping(value = "/path", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void handleRequest(#RequestBody String input) {
// ...
}
then the input parameter will constitute a String with the entire JSON object, {"first":"A","second":"B"}. What I really want is two separate Strings (or a String and an int whichever is suitable for the particular request) with just the two values (other key / value pairs that the client may send should be ignored).
If the strings were sent as request parameters instead of JSON request body it would be simple:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#RequestParam("first") String first,
#RequestParam("second") String second) {
// ...
}
I know that I can create a simple bean class that can be used in conjunction with the #RequestBody annotation that will contain both A and B when used, but it seems like a detour, since they will have different purposes inside the web app.
Dependencies:
org.springframework : spring-web : 3.1.0.RELEASE
org.codehaus.jackson : jackson-mapper-asl : 1.9.3
POJO
public class Input {
private String first;
private String second;
//getters/setters
}
...and then:
public void handleRequest(#RequestBody Input input)
In this case you need Jackson to be available on the CLASSPATH.
Map
public void handleRequest(#RequestBody Map<String, String> input)
I have written a custom WebArgumentResolver that does exactly this, combined with a custom annotation.
I don't have the source available to me now, but basically I annotated my method like this:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#JsonField("first") String first, #JsonField("second") String second) {
// ...
}
Then my JsonFieldWebArgumentResolver checks if the method parameter is annotated with JsonField, and if it is it extracts the actual type from the parameter (not quite straight-forward it turns out if you want to handle generic parameters as well, such as List<String> or List<Pojo>), and invokes Jackson's JsonParser manually to create the correct type. It's a shame I can't show you any code, but that's the gist of it.
However, that solution is for Spring MVC 3.0, and if you are using 3.1 I think you will be better off using a custom HandlerMethodArgumentResolver instead. But the idea should be the same.