Match empty path parameters in REST - java

I have a service in rest that looks like:
#GET
#Path("get-policy/{policyNumber}/{endorsement}/{type}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement,
#PathParam("type")String type){
...
}
And i want to know if there is a way that i can accept every parameter as null value if they are not sent, so if somene makes a call to my service without the params or with not all the params still can match the definition of my service.
Examples:
http://localhost:8080/service/policy/get-policy/
or this:
http://localhost:8080/service/policy/get-policy/5568
or this:
http://localhost:8080/service/policy/get-policy/5568/4
Im well aware that i can define a regex expression like in this answer, but in that case there was only 1 path param defined, what if i have more than one?
That didnt work for me but maybe im doing something wrong, i tried this with no success:
#GET
#Path("get-policy/{policyNumber: .*}/{endorsement: .*}/{type: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement,
#PathParam("type")String type){
...
}
is the only way to achive this trough a POST? Im using Jersey btw!

You have to create a complete use case scenario for this and call a general method every time if you dont want to write code multiple times.
Say: For an instance use only one parameter passed, then 2 and then all, and none
#GET
#Path("get-policy/{policyNumber: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber)
{
doSomething(policyNumber, "", "");
}
#GET
#Path("get-policy/{policyNumber: .*}/{endorsement: .*}")
#Produces(MediaType.APPLICATION_XML)
public String getPolicyIndividual(
#PathParam("policyNumber")String policyNumber,
#PathParam("endorsement")String endorsement)
{
doSomething(policyNumber,endorsement, "");
}

Related

How to call a #RestController with #RequestBody?

I have a simple servlet as follows:
#RestController
public class TestServlet {
#RequestMapping(value = "/test1")
public String test1() {
return "test1";
}
#RequestMapping(value = "/test2")
public String test2(#RequestBody TestClass req) {
return "test2";
}
public static class TestClass {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
But only the servlet not receiving parameters is working:
Works: http://localhost:8080/test1
Doesn't work: http://localhost:8080/test2?value=1234
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.lang.String
Why is the #RequestBody annotation not working? Am I missing an important piece?
One of the differences between #Controller and #RestController is that you don't have to write #RequestBody and #ResponseBody, that means that any parameter in your controller method which does not have an annotation (like #PathVariable, #ModelAttribute, ...) will implicitly have #RequestBody, and must therefore be POSTed as the HTTP entity body. So you need to send JSON/XML as part of a POST. What you have done is to send data on as part of the URL, which makes it a request parameter and not body-data, and you need #RequestParam to to extract data from the URL.
Also, I would recommend that you use the #GetMapping/#PostMapping or include the method parameter in the #RequestMapping annotation, it is highly unlikely that you want a service to be used for both POST and GET, so you should be as specific as possible in you controller method descriptions, to limit error scenarios.
The reason the second URL does not work is because when using #RequestBody the data you are sending to the endpoint needs to come through via the data attribute in the request header. When you append ?attr=value to your URL that is sending the attribute in the params header.
There are two ways to fix this:
Change your endpoint to read something like this:
public String test2(#RequestParam("value") TestClass req) {
//Endpoint code
}
Change your endpoint to read something like this:
#RequestMapping(value="test2",method=RequestMethod.POST)
public String test2(#RequestBody TestClass req){
//Endpoint code
}
and make your call similar to this (e.g. angularjs):
http.post({url:/*url*/,data:/*object to send*/});
The second option will most likely be what you want to go with because it looks like you are trying to send a json object to your endpoint and I believe you can only do that by making a POST request rather than a GET request
Just leave out the #RequestBody annotation, as this is only for POST requests.
public String test2(#Valid TestClass req) {
return "test2";
}
When you declare a controller method parameter as #RequestBody, you are wishing it to be recovered from the request body and not as a "regular" http parameter.
You could try using any kind of plugin for Firefox (RESTClient) or Chrome (PostMan) and try using one of them. You could do it using SoapUI as well.
The request should be a POST to the requested url this way:
POST http://localhost:8080/test2
You must provide http headers provinding expected Content-Type and Accept. In case of using Json, set them like this:
Content-Type: application/json
Accept: text/html (As your method returns only a String)
And then write the param to the request body. If in Json, like this:
{
"value":"the provided value"
}

Getting whole query string from REST GET service call

Is there a way to get the whole query string without it being parsed? As in:
http://localhost:8080/spring-rest/ex/bars?id=100,150&name=abc,efg
I want to get everything following the ? as one string. Yes I will parse it later, but this allows my controller and all follow-on code to be more generic.
So far I've tried using #PathParam, #RequestParam as well as #Context UriInfo with the results following. But I can't seem to get the whole string. This is what I want:
id=100,150&name=abc,efg
Using curl #PathParam using
http://localhost:8080/spring-rest/ex/bars/id=100,150&name=abc,efg
produces id=100,150
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/spring-rest/ex/qstring/{qString}")
public String getStuffAsParam ( #PathParam("qstring") String qString) {
...
}
#RequestParam using
http://localhost:8080/spring-rest/ex/bars?id=100,150&name=abc,efg
gives name not recognized.
http://localhost:8080/spring-rest/ex/bars?id=100,150;name=abc,efg
produces exception.
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/spring-rest/ex/qstring")
public String getStuffAsMapping (#RequestParam (value ="qstring", required = false) String[] qString) {
...
}
EDIT - THE APPROACH BELOW IS WHAT I'D LIKE TO FOCUS ON.
This works almost. It doesn't give me the full query string in the MultivaluedMap. It is only giving me the first string up to the &. I've tried using other characters as the delimiter and still doesn't work. I need to get this string in its undecoded state.
#Context with UriInfo using
http://localhost:8080/spring-rest/ex/bars?id=100,150&name=abc,efg
gives value for queryParams id=[100,150]. Again the name= part was truncated.
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/spring-rest/ex/qstring")
public String getStuffAsMapping (#Context UriInfo query) {
MultivaluedMap<String, String> queryParams = query.getQueryParameters();
...
}
I'm thinking the query string is being decoded which I don't really want. How do I get the whole string?
Any help is greatly appreciated.
You should have a look at the list of supported parameters:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-methods
In your case, you can add a HttpServletRequest parameter and call getQueryString():
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/spring-rest/ex/qstring")
public String getStuffAsMapping(HttpServletRequest request) {
String query = request.getQueryString();
...
}
Another way is to use the #Context UriInfo, then call UriInfo.getRequestUri() followed by URI.getQuery():
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/spring-rest/ex/qstring")
public String getStuffAsMapping(#Context UriInfo uriInfo) {
String query = uriInfo.getRequestUri().getQuery();
...
}
I would go with
http://localhost:8080/spring-rest/ex/bars?id=100,150;name=abc,efg
and have this RequestMapping
#RequestMapping(value="/spring-rest/ex/bars")
public String getStuffAsParam(#RequestParam("id")String id, #RequestParam("name")String name)
If you need access to the raw query you need to get it from the request object. Refer to this old question to get access to it. Even though the answer is not accepted it is a well researched response.
Spring 3 MVC accessing HttpRequest from controller
The following code snippet should give the query string once you get access to HttpServletRequest
httpservletrequest.getQueryString()
After I posted this I see #Andreas has posted a similar answer. Accept his answer if the solution helps you.

JAVA EE Rest conditional GET methods on QueryParams

I would like to have two GET methods on my Rest resource class.
one would react if query param has value1 and second on value2
Lets say:
#Path("/myApi")
public class MyApiService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodOne(...) {
...
return ...;
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodTwo(...) {
...
return ...;
}
How to achieve conditional routing for query params
I would like to methodOne() reacts if QueryParam is ?type=one and methodTwo() if QueryParam is ?type=two
Choosing servlet handlers based on QueryParam is not a good aproach, and by default no library gives you oportunity to do so.
The closest that comes to mind is PathParam, that is something like Path("\api\{param1}\{param2}") but it's not what you are looking for.
To achieve want your want just
unregister those methods as servlet handlers (Optional, if you don't need them outside of queryparam selection scope)
define a new one that will choose based on query param
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodThree(QueryParam('type') String type) {
return type.equals("type1") ? this.methodOne() : this.methodTwo();
}
You cannot have two methods with identical parameters for the same path.
It's not pretty, but it will work..
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod(#QueryParam("type") String type){
if(type.equals("one"))
return methodOne();
else
return methodTwo();
}

How to pass argument to a REST method

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

Resteasy #path with zero or more path parameters

I am using RESTEasy in my API development. My url is http://localhost:8080/project/player/M or http://localhost:8080/project/player
it means am pasing {gender} as path param.
my problem is how to mapp this url to REST method, i use below mapping
#GET
#Path("player/{gender}")
#Produces("application/json")
but if use it, it maps for http://localhost:8080/project/player/M but not for http://localhost:8080/project/player.
i need a regular expression to map zero or more path parameters
Thanks.
Is there any reason this must be a path parameter and not a query string ? If you change it to use the latter, then you can use a #DefaultValue annotation.
So your code would then look like the following:
#GET
#Path("player") //example: "/player?gender=F"
#Produces("application/json")
public Whatever myMethod(#QueryParam("gender") #DefaultValue("M") final String gender) {
// your implementation here
}
Path parameters (#PathParam) aren't optional. If you want to map;
http://localhost:8080/project/player/M
http://localhost:8080/project/player
You will need two methods. You can use method overloading;
#GET
#Path("player/{gender}")
#Produces("application/json")
public Whatever myMethod(#PathParam("gender") final String gender) {
// your implementation here
}
#GET
#Path("player")
#Produces("application/json")
public Whatever myMethod() {
return myMethod(null);
}
See the below link which has a sample of optional path parameters via regular expressions
RestEasy #Path Question with regular expression
You should use regex when you want have optional parameter in path.
So your code would then look like the following:
#GET
#Path("/player{gender : (/\\w+)?}")
#Produces("application/json;charset=UTF-8")
public Whatever myMethod(#QueryParam("gender") #DefaultValue("M") final String gender) {
// your implementation here
}
For more information see https://docs.jboss.org/resteasy/docs/1.1.GA/userguide/html/Using__Path_and__GET___POST__etc..html

Categories

Resources