Spring allows for a given request mapping to specify parameters which must/must not be present or have a certain value. I was wondering if it is possible to assign multiple such parameter conditions to one request mapping like:
Either the parameter is not present or has a certain value.
#GetMapping(
path = ["/data"],
produces = [APPLICATION_JSON_UTF8_VALUE],
params = ["!allStates","allStates=false"]
)
fun getData(){[...]}
It looks like every condition derived from the params are logically linked via an AND.
Additionally it seams like the second condition leads to an implied check for the existence of the parameter, which i do not want.
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-requestmapping-params-and-headers
Is sadly not that specific.
Is there a way to manipulate these params conditions? Or am i better of defining multiple request mappings?
RequestMapping Javadoc is a bit more explicit here.
Note:
... a sequence of "myParam=myValue" style expressions, with a request only mapped if each such parameter is found to have the given value.
So you are right, the conditions are combined with logical AND, and thus separate mappings should be used.
Related
I have the GET method in my Spring REST controller. This method returns the list of users by the filter.
I have a few ways to implement it:
Add #PathVariable like - /users/{type}/{age}/{name}/...(bad approach in this case)
Add #RequestParam like - /users?type=type,age=age,name=name...(usual approach in this case)
Use RequestDto (the best approach) like
public class UsersRequestDto {
private String type;
private int age;
private String name;
...
}
But I can not use GET method for this. I must use POST method with #RequestBody
And it breaks the rules. My method doesn't change state and doesn't create any entities. It workes as the GET method but in reality, it is POST.
And I have 2 ways:
Use the GET method with many parameters
Use the POST method with DTO which works as the GET method and confuses users.
Which way is better?
Short version: you might be looking for How to bind #RequestParam to object in Spring. (See also: https://stackoverflow.com/a/16942352/54734 )
On the web, we would have an html form with a GET action. When the form is submitted, the browser would process the input controls and create the application/x-www-form-urlencoded representation of the form data. For a GET action, that representation is used as the query string.
Using GET, and encoding all of the information into the query string, allows us to take advantage of general purpose caching of the results.
But the query parameters aren't accessible by themselves - they are actually embedded within the larger context of the HTTP request. We don't usually see that because, once again, general purpose components can do a lot of the heavy lifting.
So we don't see the parser that extracts the target-uri from the request, or the parser that splits the target URI into its separate components, or the parser that splits the query part into a sequence of key value pairs....
In general, what we do is ride the "general purpose" implementation as far as we can, then get off and do the rest of the work ourselves. If the framework offered no better support for object mapping, that could mean implementing that mapping ourselves.
So if our framework lacked the capability to map the query string directly to an object representation, we would hand roll that part of the implementation ourselves (either by copying each parameter "by hand", or writing our own reflection code to do the mapping automagically).
But it seems that Spring has that capability already built into it; and that it is the default option (no annotation required); you just have to be sure that the object implementation provides the interface that Spring needs to execute the mapping.
How many different parameters are you including in your query?
Personally, I prefer the option of a GET method with many different parameters. It has other benefits such as being cacheable as well. Also, compare it to something like a the URL that a Google search generates - lots of query string parameters.
The POST option feels dirty - it's a violation of what a POST should actually do (creating or updating a resource).
See these discussions: https://softwareengineering.stackexchange.com/questions/233164/how-do-searches-fit-into-a-restful-interface and REST API Best practices: Where to put parameters?
1st of all when you are using RequestParam then key will be added with & symbol not with comma(,) .
when you want to filter ( as you have mentioned) something then best approach would be to use RequestParam.
To minimize the code you can opt to "MultiValueMap" or "HttpservletRequest" .
1)HttpServletRequest
#GetMapping("/user")
public List<User> getFilteredUser(HttpServletRequest httpservlet)
httpservlet.getQuesryString() //will return all request param.
2)MultiValueMap
#RequestParam MultiValueMap<String,String> params
NOTE:- Generally POST is for create/update record.
I am in the process of learning GraphQL and have stumbled upon understanding the difference between Operation Arguments and GraphQL variables. Because IMO, both provide, client, the facility to pass in dynamic data to either mutations or queries etc.
Can someone enlighten me ?
Cheers!
Arguments and variables serve completely different functions.
Every field in a GraphQL schema can be configured to accept one or more arguments. For example:
query FilmQuery {
film (id: "ZmlsbXM6MQ==") {
id
title
}
}
Here the film field accepts an argument named id. Arguments are used to alter the value a field resolves to. In our example above, the server returns a different Film object based on the id value the client provides.
Arguments accept inputs, which can be either scalars, enums or more complex Input Object Types. Here, we're passing a String value of "ZmlsbXM6MQ==" to the argument. By writing out the value inside the query, we are said to be using a literal value.
There is nothing wrong with using literal values in your queries, but when the value passed to the argument needs to be dynamic, we need something more -- we need variables.
Variables allow us to parameterize and reuse queries. Here's our example, rewritten using a variable:
query FilmQuery($myId: ID!) {
film (id: $myId) {
id
title
}
}
Variables must first be defined at the top of your document, as part of the operation definition. Here we've defined a single variable ($myId) and told GraphQL it's type is ID!. Once defined, variables can then be used anywhere inside the operation. The actual values of any variables used in your document must be sent along with the query itself when the client actually makes the request to the server.
Again, arguments only provide a way to change how a request is executed, while using variables as inputs to those arguments is what makes a particular query dynamic and reusable.
Please note that you could use string concatenation or template literals client-side to achieve a similar effect to what variables do. You should generally avoid doing so, however, because 1) it unnecessarily creates additional work for the client and 2) serializing inputs yourself, especially complex ones like Input Object Types, can quickly become complicated and error-prone.
Im using Magnolia RenderingModel in combination with Freemarker.
I have URLs like the following:
http://anyPath/context?productTypes=XXXXX&productTypes=YYYYY
my rendering model class looks like:
class MyModel extends RenderingModelImpl {
...
private String[] productTypes;
...
}
However the mentioned array contains only the first value, but not the second.
I checked the behaviour of template directives like ctx.getParameters(). This shows the same behaviour, I get only the first value returned. But if im using ctx.getParameterValues(paramName), it returns both values.
This leads me to following questions:
How would I go, if I want to lookup how the request parameters are mapped into the rendering model, or better:
How can i change the behaviour of that ?
Can anyone acknowledge, that this behaviour is wrong ?
It used to be mentioned in documentation and I believe it still is - if you use .getParameters() you get only first value for multivalue parameter. If you want to get all the values, you need to use .getParameterValues(String param).
From what I understand reasons for that were backward compatibility.
As for changing the behavior, you would need to write your own renderer (e.g. by extending default FreemarkerRenderer and override info.magnolia.rendering.renderer.AbstractRenderer.newModel(Class<T>, Node, RenderableDefinition, RenderingModel<?>) method which instantiates and populates the model class.
Alternatively you can provide fix for above set population method and submit it to Magnolia as a patch. While the .getParameters() behavior is iirc on purpose, the model param population might not be, so you have high chance of getting that changed.
I want to have a class that has a number of fields such as String, Boolean, etc and when the class is constructed I want to have a fieldname associated with each field and verify the field (using regex for strings). Ideally I would just like specify in the constructor that the parameter needs to meet certain criteria.
Some sample code of how :
case class Data(val name: String ..., val fileName: String ...) {
name.verify
// Access fieldName associated with the name parameter.
println(name.fieldName) // "Name"
println(fileName.fieldName) // "File Name"
}
val x = Data("testName", "testFile")
// Treat name as if it was just a string field in Data
x.name // Is of type string, does not expose fieldName, etc
Is there an elegant way to achieve this?
EDIT:
I don't think I have been able to get across clearly what I am after.
I have a class with a number of string parameters. Each of those parameters needs to validated in a specific way and I also want to have a string fieldName associated with each parameter. However, I want to still be able to treat the parameter as if it was just a normal string (see the example).
I could code the logic into Data and as an apply method of the Data companion object for each parameter, but I was hoping to have something more generic.
Putting logic (such as parameter validation) in constructors is dubious. Throwing exceptions from constructors is doubly so.
Usually this kind of creational pattern is best served with one or more factory methods or a builder of some sort.
For a basic factory, just define a companion with the factory methods you want. If you want the same short-hand construction notation (new-free) you can overload the predefined apply (though you may not replace the one whose signature matches the case class constructor exactly).
If you want to spare your client code the messiness of dealing with exceptions when validation fails, you can return Option[Data] or Either[ErrorIndication, Data] instead. Or you can go with ScalaZ's Validation, which I'm going to arbitrarily declare to be beyond the scope of this answer ('cause I'm not sufficiently familiar with it...)
However, you cannot have instances that differ in what properties they present. Not even subclasses can subtract from the public API. If you need to be able to do that, you'll need a more elaborate construct such as a trait for the common parts and separate case classes for the variants and / or extensions.
How do you get the object parameters, which action method was called with at run-time, to accomplish something to the effect of the following
public ActionResult Index(Int32? x, Int32? y, DateTime? z, NumberStyles n) {
this.RouteData.Values["x"] = x
this.RouteData.Values["y"] = y
this.RouteData.Values["z"] = z
this.RouteData.Values["n"] = n
return View();
}
It seems like it should be a possible to the names and values of each parameter without this kind of tedious code.
Sometimes you can get the parameters which the action method was called with, by looking in RouteData, but this isn't always the case, particularly if the action method was invoked with an ajax request, the parameters may not show up in the RouteData, and instead show up in the Request Params.
What I'm looking for, is a generic way to get each parameter that is defined in the action method signature at run-time, and gets the parameter's actual object, run-time value, not just a string. Further more, it should work no matter how the action method was invoked, whether it may be the result of ChildActionExtensions.Action or an ajax callback.
RouteData and Request Params don't seem to have what I'm looking for.
Your code sample is setting values back into the RouteData collection. Are you trying to pass parameters to your view using the RouteData collection? That's not what it exists for, you might consider using ViewBag instead.
Or, create a POCO which contains all your properties and let the data binder do all the work (so use #model YourType in your view and pass a single argument to your view. The default model binder will map the individual argument values for you).
As far as the input value collections are concerned, there's a good reason why the value is not to be found consistently in the collections you've mentioned.
Perhaps the trick here is to clarify what's going on prior to your action being invoked. The arguments to your action method can come from more than one source. For example, it may come from:
The URL Path
The URL query string (eg: in a GET, the parameters after the question mark ?)
POSTed form data
Explicit arguments from another action
In your code sample above, the RouteData collection will only contain the value of "x" if your route has a matching parameter name.
For example: "{controller}/{action}/{x}". (this is a custom route pulling "x" from the path)
Failing that, the values will be resolved using the default model binder and will be pulled from either the query string parameters or POST data as the case may be.
The route value will take precedence. So if the above custom route was applied, the following URL:
http://www.example.com/Something/Index/1?x=2
would invoke your action with x=1. The 1 would then be found in the RouteData as pulled from the URL path and the x=2 found in the Request.QueryString would be ignored.
If you are concerned with how x got its value, then you must take into account all of the above so you know where to look. There is also the question of which route is applied to the request, but that's another topic altogether.
All the input came across the wire as text.. it was the model binder that examined your action signature and converted to the types you specified (wherever that is possible).
So, I don't think what you are asking for exists even conceptually in this setting.