Here is my method code:
#RequestMapping(value="/api/restcall", method=GET)
public response methodcall (#RequestParam (value="testId", required=false) String testId, #RequestParam (value="requestId", required=false) String requestId){
//some code
}
I want to validate the request params. Not the value but the field itself.
API call:
localhost:8080/api/restcall?requestId=abcd&testId=xyz
I want to validate that "requestId" and "testId" are sent correctly if sent. Not the value, but the key itself. NOTE: The requestParams are not mandatory fields.
So if below API call is made:
localhost:8080/api/restcall?request=abcd&test=xyz
I want the code to validate that the requestparams are not correct. I tried the #Validate annotation and #Valid annotation. Both did not work.
When incorrect call is made like above, the code is going through as the fields are not mandatory.
I want to know what params are coming in if testId and requestId are not sent in. If I have this information, I can do the validation.
The validation of REST invocations doesn't work in this way.
This validates the values of the sent parameters, not the names of them.
So as the required attribute is set to false for the parameters, no violation constraint occurs.
The invalid names of the sent parameters are probably ignored by the Jackson processing.
If you want to perform such a validation, you should use a custom validator or a custom validation.
For example :
String errorMsg = "";
if (StringsUtil.isEmpty(testId)){
errorMsg+="testId param name missing";
}
if (StringsUtil.isEmpty(requestId)){
errorMsg+="requestId param name missing";
}
if (!errorMsg.equals("")){
throw new ValidationException(errorMsg);
}
You can get a map with all params fields and values with: #RequestParam Map<String,String> allRequestParams. Then you can use containsKey to check for a field.
Related
How to fail on invalid query parameter name with RESTEasy?
Consider a valid REST request like this one: /list?sort-by=date
Then, user makes this request: /list?sort_by=date
See that user replaced hyphen with underscore. It works, but it will ignore parameter and use default sorting (param not mandatory).
With Jackson, if a JSON with invalid member is sent it throws an Exception. I would like a similar behavior to query params (header params would be awesome too). Tested with #BeanParam, but apparently it doesn't use Jackson in this case.
RESTEasy version 3.15.1.
You have to check that in your code. Query params are not in json in standard, you can do that with a class with string constructor.
In fact "sort_by" is not bind to a method parameter, so it's ignored.
If you want that "sort-by" to be mandatory you have to do that in your code :
Required #QueryParam in JAX-RS (and what to do in their absence)
Currently since RESTEasy is built on top of a Servlet, it does not distinguish between URI query strings or url form encoded parameters. Like PathParam, your parameter type can be an String, primitive, or class that has a String constructor or static valueOf() method.
https://docs.jboss.org/resteasy/docs/3.15.1.Final/userguide/html_single/#_QueryParam
#RestController
public class MyController {
#GetMapping("/get)
public void get(Map<String, String> params) {
println(params.get("optional")); //"null"
}
#PostMapping("/post)
public void post(Map<String, String> params) {
println(params.get("optional")); //null
}
}
localhost:8080/get?key=value&optional=null
Result: the value of the key optional will be "null" written as String, not as null type.
Whereas a POST request would work as follows:
{
"key": "value",
"optional": null
}
Question: how can I make the GET request behave the same as POST? Means, how can I tell spring to interpret the null string in a GET as a real null?
You can't pass null via HTTP query parameter like you do it in JSON. Because null within an HTTP query has no special meaning and is treated like any other string.
Instead just don't pass optional parameter at all
localhost:8080/get?key=value
You could do something like this as well.
#RequestParam(name = "optional", required = false) String optional
Spring Docs
Like #Nikolai says, null has no special meaning in the query. The query is often called the Query String such as in AWS API Gateway, which is more descriptive that it tells you that it is a String, it isn't a Map, Strings only have chars encoded, there is no concept of a null in this context.
IMO it isn't good practice to use a Map<String,String> params if you can avoid it, rather prefer strong types and list all the possible query params with optional parameters for non-required inputs. If you want the users to specify a Map it should be in the BODY, but a GET with a body feels wrong to me so you might need to then change the HTTP method.
If you have many parameters, and that's why you are using a Map, remember some browsers limit the chars in a URL to 2048, so it can be dangerous and you may have a case whereby the user cannot specify all the parameters they need to because of this limit.
TL;DR: Map<String,String> should be in request body.
I am working with HttpServletRequest, and I must output all headers and information from that object.
for the headers I am using getHeadersNames()
Enumeration<String> headerEnums = servletRequest.getHeaderNames();
while (headerEnums.hasMoreElements()) {
String elementName = headerEnums.nextElement();
String elementValue = servletRequest.getHeader(elementName);
sb.append("Header.").append(elementName).append("=").append(elementValue).append(", ");
}
and afterwards I am retrieving all parameters using getters, for example:
sb.append("getAuthType").append("=").append(servletRequest.getAuthType());
I am getting duplicate arguments for example Header.content-type and ContentType from getContentType()
my questions:
There is a nice way to output all servletRequest parameters without iterate over headers, attributes and getters? like toString()?
How can i avoid retrieving duplicate arguments without having a temporal set?
Is it possible to have an header inside Headers where its getter is empty? for example: content-type exist in Headers but getContentType() is null?
My answer is in the context of Apache Tomcat (8.5).
Is it possible to have an header inside Headers where its getter is empty? for example: content-type exist in Headers but getContentType() is null?
It's not possible, unless there is a bug. Those methods query the same internal data structure that contains the headers.
How can i avoid retrieving duplicate arguments without having a temporal set?
You are querying the same data structure twice - so it's pretty simple - do not ask twice for the same thing. Either use the headers, or use the methods from HttpServletRequest. The only difference is, that when using the methods, you'll get a default value (like -1, if the Content-Length is unknown), while you'll get NULL if you ask for a missing header.
There is a nice way to output all ServletRequest parameters without iterate over headers, attributes and getters? like toString()
At least I'm not aware of such standard method.
I have the following POST response in JAX-RS.
#POST
#Path("/save")
public Response saveS(#FormParam(key) String value) throws SQLException {
return Response.ok("TODO", MediaType.APPLICATION_JSON).build();
}
The parameter that is received could be called name or age or many other things. I have identified it as key in the code (obviously it doesn't work).
How can I retrieve the name of that parameter?
Thanks
The parameter that is received could be called name or age or many other things. I have identified it as key in the code (obviously it doesn't work).
As you already found out it doesn't work that way because the #FormParam is expecting the name of a form parameter as it is defined in the corresponding HTML form. That means you should know which form parameter you want to assign to the param (value in this case) of the method.
Here is the definition of the #FormParam annotation extracted from the JAX-RS specification:
FormParam Parameter
Specifies that the value of a method parameter is to be extracted from a form parameter in a request entity body. The value of the annotation identifies the name of a form parameter. Note that whilst the annotation target allows use on fields and methods, the specification only requires support for use on resource method parameters.
And in addition to that you should add the #Consumesannotation to your resource method as follows:
#POST
#Path("/save")
#Consumes("application/x-www-form-urlencoded")
public Response saveS(#FormParam(key) String value) throws SQLException {
return Response.ok("TODO", MediaType.APPLICATION_JSON).build();
}
Update:
I haven't tried myself, but you can try and tell me if it works. Here you should get all the params so that you can parse all the form fields:
#POST
#Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// parse the map here
}
I am calling services and want to map the data from path param and from request body. web-services call is type of POST.
Problem here is if i use #Form then I am getting only path param
Here are the scenario.
Case1 Url :- Response updateDepartment(#Form #Valid Department departmentObject)
I am getting path param value as departmentNumber, departmentSNumber and departmentName
but not getting request body which contain addRequest[{ }] and removeRequest[{ }]
In case If i use only #Valid then
Case 2 Url :- Response updateDepartment(#Valid Department departmentObject)
In this case, I am getting addRequest[{ }] and removeRequest[{ }] values.
but Object but now missing with departmentNumber, departmentSNumber and departmentName
Department.java
public class Department
{
#PathParam(DEPTNUMBER_PARAM)
private String deptNumber;
#PathParam(DEPT_S_PARAM)
private String deptSNumber;
#PathParam(DEPARTMENT_NAME)
private String departmentName;
private List<String> addRole;
private List<String> removeRole;
}
How to map both the values form #PathParam as well as request body values.
Here is the call
http://localhost:8080/myweb/departments/1234/4321/finance
{
"addRole": [
101,
181
],
"removeRole": [
42,
12
]
}
Why don't you use this:
Response updateDepartment(#Valid Department departmentObject, #PathParam("departmentNumber") String departmentNumber....)
What you want it will not work. I will try to explain.
First of all, I think you are using resteasy not JAX-RS reference, correct?
In RestEasy for #Form annotation it said:
This can be used as a value object for incoming/outgoing request/responses. You can re-use #*Param annotations on fields/methods of the parameter to unmarshall from the request or marshall to the response depending if you're using server-side JAX-RS or the Resteasy client framework
In your case, you use #PathParam on the fields of the parameter, that is why was populated.
When you do not use #Form, whatever type you specify for the parameter it tries to match with request body, which, in your case contain only the two arrays and not the PathParam. It will not look into the path params for anything else, thus ignoring your annotation.