How to handle optional parameters in CXF restful webservices - java

I have followed this link for building CXF Restful webservices url link.
If suppose my url is as mentioned below :
http://localhost:8080/CxfRestService/rest/employeeservices/getemployeedetail?employeeId=1&empProfession=software
Here,"empProfession" parameter is optional for me.
So,eventhough if I omit that parameter and hit the below url, I should get the required response. http://localhost:8080/CxfRestService/rest/employeeservices/getemployeedetail?employeeId=1
Can anyone please help me out how to use optional parameters in the CXF Restful webservices.

Option 1 - Declare the parameter and check if != null
public Response getEmployeeDetail(#QueryParam("employeeId") String employeeId, #QueryParam("empProfession") String empProfession);
Option 2 - Declare en object to receive all known parameters
public Response getEmployeeDetail(#QueryParam("") EmployeeFilter filter) ;
public class EmployeeFilter {
public void setEmployeeId(String id) {...}
public void setEmpProfession(String p) {...}
}
Option 3 - Do not declare parameters and parse the URI. This option could be useful if you can accept non-fixed parameters
public Response getEmployeeDetail( #Context UriInfo uriInfo) {
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
String employeeId = params.getFirst("employeeId");
String empProfession = params.getFirst("empProfession");

In fact, all parameters in CXF are not mandatory and you cannot change this using #QueryParam (as you can do compared e.g. with Spring-REST using #RequestParam(required=false)).
The solution is to add the #NotNull javax.validation annotation to indicate that a parameter is mandatory.
This way, you can use
CXF3 ValidationFeature to validate it automatically using #Valid.
CXF3 SwaggerFeature will also render mandatory parameters in the API documentation
CXF2 perform bean validation manually
See the CXF3 ValidationFeature for more info on using the javax.validation annotations: https://cwiki.apache.org/confluence/display/CXF20DOC/ValidationFeature
More about the CXF3 Swagger Feature here: http://cxf.apache.org/docs/swagger2feature.html).
This answer is related: Required #QueryParam in JAX-RS (and what to do in their absence)

Related

Missing Request header "Accept" with Spring 5.x

I was using Spring version 4.x, and with the upgrade to 5.x - I have noticed that some of the API requests are failing (MissingRequestHeaderException) if the Accept header is not provided in the request.
The interface doesn't really need them, as it is not being used. The API's without it in the interface works fine. A solution would be to remove it from all the API's wherever it's there. But that's not a path we want to take now, I am looking for a general solution that could be applied to all API's without having to change each one separately.
Is there a way I could ask Spring to ignore this parameter in the interface ?
Or maybe handle the MissingRequestHeaderException so as to ignore it and process the API request, is that possible?
The API Interface:
public Void setEmployeeDetails( #PathVariable( "employeeId" )Integer employeeId, #Valid #RequestBody EDetails eDetails, String accept )
The API Controller implementing the interface:
Void setEmployeeDetails( #ApiParam(value = "ID of the employee.",required=true ) #PathVariable("employeeId") Integer employeeId,
#ApiParam(value = "" ,required=true ) #Valid #RequestBody EDetails eDetails,
#RequestHeader("Accept") String accept)
Javadoc of MissingRequestHeaderException says:
ServletRequestBindingException subclass that indicates that a request header expected in the method parameters of an #RequestMapping method is not present.
Checking the Spring source code, it also seems like that exception is only thrown by RequestHeaderMethodArgumentResolver, which says:
Resolves method arguments annotated with #RequestHeader except for Map arguments. See RequestHeaderMapMethodArgumentResolver for details on Map arguments annotated with #RequestHeader.
An #RequestHeader is a named value resolved from a request header. It has a required flag and a default value to fall back on when the request header does not exist.
So it would seem that if you're getting that error, it's because your code is asking for the Accept header and did not specify required=false, e.g.
#RequestMapping(...)
public void foo(#RequestHeader(name="Accept", required=false) String accept) {
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
// Missing!
...
}

Is #Consumes annotation required or optional in the DELETE method Jersey

I'm new in jersey rest service and I want to understand in this example the utility of adding #Consumes annotation to a delete method in this case this is the code it's work well (in a video ), is the #Consumes annotation optional here ? Thanks in advance
#path("activities")
public class ActivityResource {
#DELETE
#Path("{activityId}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response delete(#PathParam("activityId")String activityId) {
activityRepository.delete(activityId);
return Response.ok().build() ;
}
}
Is the #Consumes annotation optional here ?
Yes, I would even say that it is not needed as you have only one parameter and it is a PathParam which means that it will be extracted from the path.
The annotation #Consumes is used to indicate the JAX-RS implementation how to dynamically parse/deserialize the body of your request in order to have it as parameter in a more convenient type.
For example:
#POST
#Consumes("application/xml")
public void registerUser(User user) {
...
}
In this example, we indicate that the body of the request is of type application/xml, the JAX-RS implementation will then parse the body's content as an XML to finally get an instance of User.
NB: The HTTP method used has no effect on whether or not #Consumes is needed, only the need to parse the body matter.
A DELETE should not be interested in anything that is in the request body. It should only identify the resource to be deleted based on the URI.
Remove the #Consumes, it is wrong here.
Also think about returning a HTTP status 204 No Content instead of 200 OK. After deleting a resource, there is nothing to return. You should also remove the #Produces because of this.

How to find the URL of a RESTful API inside of said API

Say I have this endpoint:
#GET
#Path("/{product}")
#Produces(MediaType.APPLICATION_JSON)
public String getProduct(
#PathParam("product") final String product) {
return createSignature(<<PLACE COMPLETE URL HERE>>);
}
How can I know the complete URL that is being called from inside the endpoint in order to maybe create a signature based on that? Thanks
There are several ways.
Generally you can add special parameter to method or a field to your resource class. Special parameter is recognized by type (HttpServletRequest or UriInfo) and should be marked using annotaiton #Context.
#StormBringerX already mentioned that the information may be passed using method parameter (+1). I personally prefer to add this as a field of your class because I think this is clearer and allows creating methods that accept only application level parameters.
You can access the original request by adding #Context HttpServletRequest request as a parameter to your method. You can then access anything you want to do with the request.

Spring MVC Controller pre process request body

I am working on spring REST APIs. In requirements, there are 2 POST requests with same URL but different request body. Since Spring MVC must have unique mappings across controller, I have to pre-process the request body to map to a specific POJO.
On the basis of session_type in request body, I have to map the request to specific POJO (JSON -> JAVA POJO).
For example, if 'session_type' in request body is 'typeX' then the request should map to ClassX POJO. If 'session_type' in request body is 'typeY' then the request should map to ClassY POJO.
If there a way to do it using some kind of requestbody annotation?
If you want to bind typeX and typeY, then you definitely need 2 handlers. But, why wouldn't we use param option of #RequestMapping:
#RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeX")
public String handleTypeX(#RequestBody #ModelAttribute TypeX typeX){
//TODO implement
}
#RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeY")
public String handleTypeY(#RequestBody #ModelAttribute TypeY typeY){
//TODO implement
}
If you need some preparations (f.e. normalize params or perform model binding manually), then the approach above you may combine along with #InitBinder, but please note, that #InitBinder needs exact ULR's rules along with #ModelAttribute parameters in handlers.
EDIT: In Spring MVC there is no possibility to use 2 handlers for exact URL, i.e. when method/URL/params/consumes type are the same.
Thus I suggest use unified handler, where you would check necessary parameter and then manually convert into corresponding class. For finding necessary class I suppose it would be better to use Strategy pattern:
//class resolver according "session_type" parameter
//note, that you can use Spring autowiring capabilities
private final Map<String, Class> TYPES_CONTEXT = new HashMap<String, Class>(){
{
this.put("x", TypeX.class);
this.put("y", TypeY.class);
//TODO probably other classes
}
}
#RequestMapping(method = RequestMethod.POST,
value = "/url")
public #ResponseBody String handleAnyType(#RequestBody Map<String, String> body){
String sessionType = body.get("session_type");
//TODO handle case if sessionType is NULL
Class convertedClass = TYPES_CONTEXT.get(sessionType);
//TODO handle case if class is not found
Object actualObject = objectMapper.convertValue(body, convertedClass);
//now we use reflection for actual handlers, but you may refactor this in the way you want, f.e. again with Strategy pattern
//note that current approach there should be contract for methods names
Method actualHandler = this.getClass().getMethod("handle" + actualObject.getClass().getSimpleName());
return (String)actualHandler.invoke(this, actualObject);
}
public String handleTypeX(TypeX typeX){
//TODO implement
}
public String handleTypeY(TypeY typeY){
//TODO implement
}
//TODO probably other methods
This approach doesn't handle validation and some things were omitted, but I believe this might be helpful.
I think you should created controller with one method for both types, and call required component\method in it depending on typeX or typeY.
GETs shouldn't have request bodies, or at least if they do, the server side isn't required to do anything with them. As you describe it, this API isn't RESTful.
Assuming you don't care about that, try creating a controller method that takes a parent class of TypeX and TypeY, or interface that both TypeX and TypeY implement, annotate it with #SomethingMeaningfulToYou, then use a web argument method resolver to instantiate the child class you want.
It's a hack around a broken API though.
there are 2 POST requests with same URL but different request body
For a RESTful interface, the same URL should always indicate the same resource. The body of a request may contain different representations of that resource. You could create different HttpMessageContverter classes for the two different kinds of representation.

Spring - Abstracting url mapping to handle common url parameters

Assume the following setup:
We have multiple commands mapped to different URLs, each of these with its own body, which we can capture using mappings, like:
#RequestMapping(value = "url1/{param}/command", method = RequestMethod.POST)
#ResponseBody
public Response command1(#PathVariable("param") String param,
#RequestParam(value = urlParam) Param urlParam,
#RequestBody Request request) {
...}
We have several cases where the same parameter repeats in several urls, specifically the URL parameter. Since we have several such variables, today we manually add them to each mapping which is error prone and too verbose.
Is there anyway of routing all mappings through an initial mapping, capturing all those url parameters, and thus remove the clutter from all other mappings?
If you switch from Spring MVC to any JAX-RS framework (e.g. Jersey, Apache Wink), you can use subresources:
#Path("/parent/{id}")
class ParentResource {
#Path("/child1")
Child1Resource getChild() {
....
}
#Path("/child2")
Child2Resource getChild() {
....
}
}
Pay attention that methods with #Path annotations are not annotated with HTTP Methods, so any relevant HTTP request matching the url will propagate into the subresources.
Another suggestion to reduce the error-proning: use constants (public final static String) as parameters both when you create the url and when you use the parameter. This makes it a little bit more verbose, but reduce the error-proning. It can be used both with Spring-MVC and JAX-RS. Don't forget that it's possible to put constants inside the annotation values.
Hope this helps.

Categories