Remove "/" from api call when optional parameter is null - java

We are using RESTful Web Services (Jersey) for API calls on java. While API needs optional parameter, we are doing as:
api-interface/user/userid/9000/companyid/90909/{optionalparameter*}
and we have to call this api when there is no optional parameter as:
api-interface/user/userid/9000/companyid/90909/
What needed is:
Case:1 If optional parameter exists
api-interface/user/userid/9000/companyid/90909/name/john/address/MA/age/34
Case:2 If Optional parameter doesn't exists.
api-interface/user/userid/9000/companyid/90909
My present implementation is:
#GET
#Path("user/companyid/{companyid}/userid/{userid}/{optionalparameter:.*}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserList(#PathParam("companyid") String companyId, #PathParam("userid") String userId,
#PathParam("optionalparameter") String syncDate) throws BadRequestException, InternalServerException {
//parsing the param.
}
In above code, I need to add trailing "/" but I am looking the way to remove this trailing "/" if anybody doesn't wants to pass those param.
I followed this link but it didn't worked while the preceding parameter's length is more then 1.
Please, Suggest me the best way.

Looking at your reference, have you tried this:
#Path("userid/{userid}/companyid/{companyid}{optparam:(/[^/]+?)*}")
public Response getLocation(
#PathParam("userid") int userid,
#PathParam("companyid") int companyid,
#PathParam("optparam") String optparam) {
String[] params = parseParams(optparam);
...
}
private String[] parseParams(String params) {
if (params.startsWith("/")) {
params = path.substring(1);
}
return params.split("/");
}
That should work, giving you all the parameters in a single array.
EDIT: I have updated the search string and verified it on a local install.

Related

Get only URI from HttpServletRequest

I have an API - http://localhost:8080/api/version/<versionA> where versionA is a Path Parameter.
HttpServletRequest getRequestURI() returns -> /api/version/<versionA>
How do we ensure that only /api/version is returned back? Is there any way to generalize this for all endpoints and return only the first part of the URI excluding path params?
For example -
/api/version/<param1> Should Return /api/version
/api/<param1> Should return /api
/api/version/<param1>/name/<param2> Should return /api/version
Path Parameter is not a Query Parameter; it is rather a part/segment of the URL Path. So, there is no (and there should not be) built-in Servlet API method, that will return your, "custom-sub-stringed" path.
Q: Why?
A: Because you may have more than one path parameters /a/b/<param1>/<param2>/c/<param3>
Is there any way to generalize this for all endpoints and return only the first part of the URI excluding path params?
In your case, one option would be to implement some utility method, which will find the the lastIndexOf "/" and then will return the substring to that last "/".
It depends a bit on how you've constructed things but let's take an example.
http://localhost:8080/sample/rest/v1/classLevel/methodLevel/param1/param2/something/param3
and a service defined as:
#Path("/v1/classLevel")
public class NewService {
#Path("/methodLevel/{param1}/{param2}/something/{param3}")
public Response getSomeStuff(#PathParam("param1") String param1,
#PathParam("param2") String param2,
#PathParam("param3") String param3,
#Context HttpServletRequest request) {
return Response.ok().build();
}
}
This webapp is deployed under the context root "sample". That means that if I were to go to http://localhost:8080/sample/ I'd get the root element (perhaps index.html) for the webapp. In my Application I have:
#ApplicationPath("/rest")
public class RestApplicationConfig extends Application {
// intentionally empty
}
So the parameters in the URL are:
request.getServletPath() returns "/rest"
request.getContextPath() returns "/sample"
request.getPathInfo() returns "/v1/classLevel/methodLevel/param1/param2/something/param3"
So I believe that what you want is request.getContextPath() + request.getServletPath(). But it's a bit unclear which part you really need.
EDIT
To find out what path is at the class level a little reflection is needed. Within a class that is being called (i.e. non-static methods of the NewService class above) you would be able to get that with:
public String getClassLevelPath() {
if( this.getClass().isAnnotationPresent(Path.class)) {
Path annotation = this.getClass().getAnnotation(Path.class);
return annotation.value();
}
return null;
}
As my class is defined, this returns "/v1/classLevel". I would personally cache this in something like a static variable as it's not going to change during runtime unless you're doing something else to change it.

how to pass several parameters in get request

I'm trying to check if my method works through the API
#GetMapping(value = "/ads/in/rubrics/{ids}")
public List<Ad> findAllAdInRubricByIds(#PathVariable("ids") List<Integer> ids) {
return adService.findAllAdInRubricByIds(ids);
}
how can i set some parameters in get request?
that's how i tried
http://localhost:9999/mvc/ad/ads/in/rubrics/ids&ids=1&ids=2
http://localhost:9999/mvc/ad/ads/in/rubrics/ids&ids1=1&ids2=2
always get error 400 Bad Request
You're confusing PathVariables with RequestParams.
A PathVariable is a variable in the request path. It doesn't need to be the last character.
#GetMapping("/api/{version}/foo/{idFoo}")
public Void getFooNumber(#PathVariable("version") Integer version, #PathVariable("idFoo") Integer idFoo){
return "1";
}
Since PathVariables are part of the path, they're always required. If you don't incluide them in the request you'll end up invoking another endpoint or getting a 404 if the request can't be mapped to any endpoint.
The RequestParams are the parameters received at the end of the request URL, after the "?" character.
#GetMapping("/api/foo")
public Void getFooNumber(#RequestParam(value="version", required=false) Integer version, #RequestParam(value="idFoo", required=true) Integer idFoo){
return "1";
}
With RequestParams you can define for each one of them if it's required or not.
You can also mix them and have in the same method PathVariables and RequestParams.
In the first example the request URL would be ".../api/1/foo/25", while in the second example it would be ".../api/foo?version=1&idFoo=25"
As for having an array or a list, if you define the parameter as a List you can send multiple parameters of the same name:
#GetMapping("/ads/in/rubrics")
public Void findAllAdInRubricByIds(#RequestParam(value="ids", required=true) List<Integer> ids){
return adService.findAllAdInRubricByIds(ids);
}
In this case, you can use ".../ads/in/rubrics?ids=1&ids=2&ids=3&ids=4"
http://localhost:9999/mvc/ad/ads/in/rubrics/?ids1=1&ids2=2
For the first parameter use a ? and after that for each additional parameter a &

I am using Postman, to pass the data to a REST api but my variable is showing null value

My main question is how to pass a (Map, String) to a REST API, I know if I use #RequestBody all the passed contents are stored to map but what can be done to pass map as well as any other parameters REST API.
#GetMapping(path="/invoices")
public String invoiceReceived( Map<String,Object> invoice,String format) throws MessagingException {
System.out.println(format); // this prints NULL
return "returnValue";
}
So I tried using PathVariable but they throw exception. What can be done?
#GetMapping(path="/invoices/{invoiceData}/{format}")
public String invoiceReceived(#PathVariable("invoiceData") Map<String,Object> invoice,
#PathVariable("format") String format) throws MessagingException {
System.out.println(format); // this prints NULL
return "returnValue";
}
What should I do to accept a map and a variable as input? And what should be the JSON file look like which should be given as input?
{
"invoiceData":[{"invoiceId":"23642",
"clientName":"Client",
"amount":"23742.67",
"email":"client#abc.com"
}],
"format":"html"
}
This question was identified similar to another question, So I am trying to explain how is this different, I know that I can use #RequestBody to get all the variables in the map, but The call will be made with two parameters some of which will be stored in map but one parameter will be used for another variable. So how can I send a map along with any other variable?
I think you can use query strings and path variables.
If you declare a controller's method like:
#GetMapping(path="/invoices")
public String invoiceReceived(#RequestBody Map<String,Object> invoice, #RequestParam String format) {
...
}
the url to which the request is send and the JSON request body will be something like below.
The url:
http://localhost:8080/invoices?format=html
The JSON request body:
{
"invoiceId":"23642",
"clientName":"Client",
"amount":"23742.67",
"email":"client#abc.com"
}
Also you can use a path variable like:
http://localhost:8080/invoices/html
#GetMapping(path="/invoices/{format}“)
public String invoiceReceived(#RequestBody Map<String,Object> invoice, #PathVariable String format) {
...
}

How to create REST API with optional parameters?

I need to implement an API with these path params.
#Path("/job/{param1}/{optional1}/{optional2}/{param2}")
Can the second and third params by optional? So the client need not pass these, but have to pass the first and last.
If this is not possible, then is it recommended to rearrange the params in this way?
#Path("/job/{param1}/{param2}/{optional1}/{optional2}")
How to provide the optional params?
It might be easier to turn the optional path parameters into query parameters. You can then use #DefaultValue if you need it:
#GET #Path("/job/{param1}/{param2}")
public Response method(#PathParam("param1") String param1,
#PathParam("param2") String param2,
#QueryParam("optional1") String optional1,
#QueryParam("optional2") #DefaultValue("default") String optional2) {
...
}
You can then call it using /job/one/two?optional1=test passing only the optional parameters you need.
You can match the entire path ending in the REST request
#Path("/location/{locationId}{path:.*}")
public Response getLocation(
#PathParam("locationId") int locationId,
#PathParam("path") String path) {
//your code
}
Now the path variable contain entire path after location/{locationId}
You can also use a regular expressions to make the path optional.
#Path("/user/{id}{format:(/format/[^/]+?)?}{encoding:(/encoding/[^/]+?)?}")
public Response getUser(
#PathParam("id") int id,
#PathParam("format") String format,
#PathParam("encoding") String encoding) {
//your code
}
Now if you format and encoding will be optional. You do not give any value they will be empty.
Rearrange the params and try the following:
#Path("/job/{param1}/{param2}{optional1 : (/optional1)?}{optional2 : (/optional2)?}")
public Response myMethod(#PathParam("param1") String param1,
#PathParam("param2") String param2,
#PathParam("optional1") String optional1,
#PathParam("optional2") String optional2) {
...
}
to make request parameter optional set #requestparam to false in controller class
(#RequestParam(required=false)

How to map a path suffix to a query parameter using Java Jersey?

Background: we have build a RESTful API using Jersey a while ago where we map the uri /items.json to a json array of ids and /items/{id}.json to the json object of a single item. Now we want to create a list with some meta data for each item and would like to use a selector like /items.data.json, similar to apache sling.
So far: I just extended the UriConnegFilter to parse the uri for additional suffixes, something like this:
public class UriSelectorFilter extends UriConnegFilter {
protected List<String> selectors; // this list is populated in the constructor
public ContainerRequest filter(ContainerRequest request) {
super.filter(request);
// search for suffix in last path segment, see http://java.net/projects/jersey/sources/svn/content/trunk/jersey/jersey-server/src/main/java/com/sun/jersey/api/container/filter/UriConnegFilter.java?rev=5034
final String[] suffixes = segment.getPath().split("\\.");
for (int i = suffixes.length - 1; i >= 1; i--) {
final String suffix = suffixes[i];
if(selectors.contains(suffix)) {
request.getQueryParameters().putSingle("selector", suffix);
final int index = path.lastIndexOf('.' + suffix);
path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();
suffixes[i] = "";
}
}
if (length != path.length()) {
request.setUris(
request.getBaseUri(),
request.getRequestUriBuilder().replacePath(path).build());
}
return request;
}
}
This filter works perfect, it finds the selector part of my uri and adds a query param to the request object. But in my Resource I added a #QueryParam attribute, which is only filled with the default value and not the added query value:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getItemsJSON(#DefaultValue("id") #QueryParam("selector") String selector) {
// query param is not filled with the selector that was found in the UriSelectorFilter
}
Does anybody have a suggestion how I can provide my resource with the selector that was detected? Is there a better way than using a QueryParam? (Note: if I add the query to my url like '?selector=something' then the attribute is filled correctly.)
Any help is very appreciated.
You need another argument that is annotated with #PathParam, and you need to specify in your #Path annotation (on the method or class) how to bind these bits together. For example, to deal with a path like /items/foobar42/data.json you might do this:
#GET
#Path("/items/{item}/data.json")
#Produces(MediaType.APPLICATION_JSON)
public Response getItemsJSON(#PathParam("item") String itemId,
#DefaultValue("id") #QueryParam("selector") String selector) {
// Now you've got an itemId and a possible selector...
}
Trying to do all the mapping with a filter… that seems difficult to me given that there's a nice declarative way of doing it instead. You can even specify a regular expression in the #Path to allow for matching a more complex variable section; I do that in my own code to create a method that can serve a whole hierarchical filesystem.
(Note that the {braced} item in the #Path should match the name in the #PathParam annotation, and you can have multiple items matched from the path if necessary; just use several #PathParam-annotated arguments.)

Categories

Resources