First off, this is related to Spring Data Rest: How to search by another object's key? which appears to be resolved in https://jira.spring.io/browse/DATAREST-502
My issue is (I believe) and extension of this. I'm seeing the following behavior:
I have two repository queries defined e.g.
Person findByAccount(#Param("account") Account account));
Collection<Person> findByAccountIn(#Param("accounts") Collection<Account> accounts));
Both search methods are exposed via spring-data-rest. I can access the first using a url such as http://localhost:8080/people/search/findByAccount?account=http://localhost:8080/accounts/1
I can access the second method using a url such as http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1, but if I try to pass in MULTIPLE accounts, such as
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1,http://localhost:8080/accounts/2,
It will run the query except will IGNORE the first account (http://localhost:8080/accounts/1) and only search based on the second (http://localhost:8080/accounts/2)
What is the proper technique for passing in a Collection of entities to a repository argument over the REST API? I find it works great for a single entity, but not for a Collection. Note that both of these repository methods are working as expected when directly accessing the JpaRepository.
Also note that these queries seem to work if the collection is of some primitive type, for example findByAccountIdIn(#Param("accountIds") Collection<Long> accountIds) is accessible with intended functionality via http://localhost:8080/people/search/findByAccountIdIn?accountIds=1,2. This leads me to believe it's possibly an error in the way a list of URIs is passed into a query method which expects a Collection of corresponding entities.
Thanks in advance for any help!
Try repeat the query parameter as most servers will interpret this as a list. It might not be the prettiest solution but should work.
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1&accounts=http://localhost:8080/accounts/2
I know that this is forever old, but I found the answer.
I will put this here for anyone else who should wander this way:
How to use List in endpoint exported by Spring Data REST?
List<Person> findByAccountIn(#Param("accounts") Account... accounts);
the request would look like this:
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1&accounts=http://localhost:8080/accounts/2&accounts=http://localhost/accounts/anotheraccountid
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.
We're using spring-data-rest 2.6.8 with spring-boot 1.5.8 and it's awesome! We found some strange behavior, nonetheless.
When we do a GET to /rest/students/search/findByTeacher?teacher=/rest/teachers/1 everything runs smoothly. SDR converts the teacher URI into a teacher Entity and we get a list of students.
When we provide a different URI (that resolves to the same object), the system can't do the conversion: /rest/students/search/findByTeacher?teacher=/rest/class/2/teacher
Currently we are doing this in two steps. First we GET the /rest/class/2/teacher and then we use the _links.self.href (/rest/teachers/1) to do our search.
Is there a way to configure SDR to avoid this 2-step process?
I do not think it is possible. Spring Data Rest when resolving the links works in a way that basically it grabs the url, removes baseUri from the beginning, then it tries to match next part of the URL to the repository {teachers} and then queries the repository using findOne method. In this case the url /rest/teachers/1 is simply identifier of the resource (without hateoas it would be sth like teacherID=1)
The problem with querying /rest/class/2/teacher is that you do not know to what it will be resolved - it might be single element, it might be a list, it might be a null etc. because this is not an identifier to the resource, but a link to another one.
I'm trying out Spring Data with MongoDB and REST as shown here. One thing I noticed is that to sort results, you add a query parameter named .dir with a value of "asc" or "desc".
In many REST APIs I've used, the mechanism for sorting was to simply put a minus ("-") symbol in front of the property name in the sort (or order) parameter.
Is there any way I could customize Spring to allow for this behavior?
I remembered I stumbled on this thread before I made the customized resolver. You can use SimpleSortHandlerMethodArgumentResolver class on https://github.com/sancho21/spring-data-commons/commit/6c90a9cfcb50b2ed0e7a25db0cfd64d36e7065da
Please comment to support its adoption on https://github.com/spring-projects/spring-data-commons/pull/166/files
As for reminder, in order to use this class, you need to inject an instance of it into the existing the constructor of existing PageableHandlerMethodArgumentResolver instance.
I am working on a REST service which uses Spring 4.x. As per a requirement I have to produce several different views out of same object. Sample URIs:
To get full details of a location service: /services/locations/{id}/?q=view:full
To get summary of a location service: /services/locations/{id}/?q=view:summary
I have thought of two solutions for such problem:
1. Create different objects for different views.
2. Create same object, but filter out the fields based on some configuration (shown below)
location_summary_fields = field1, field2
location_detail_fields = field1, field2, field3
Could someone help me to understand what could be an ideal solution? I am not aware of any standard practice followed for this kind of problems.
Thanks,
NN
In my opinion the best option is to use separate POJOs for different views. It's a lot easier to document it (for example when you use some automated tools like Swagger). Also you've to remember that your application will change after some time, and then having one common POJO could make troubles - then you'll need to add one field to one service and don't expose it through another.
See this article on how google gson uses annotations to convert a Java Object representation to a json format : http://www.javacreed.com/gson-annotations-example/
Since you want two different representations for the same object you could roll your own
toJson method as follows :
a) Annotate each field of you model with either #Summary, #Detail or #All
b) Implement a toJson() method that returns a json representation by examining the annotations for the fields and appropriately using them
If you need an XML representation same thing, except you would have a toXML().
I understand that a IQueryable cannot be serialized. That means that queries can not be serialized, sent to a webservice, deserialized, queried and then sent back.
I was wondering if it is possible to convert a hibernate linq query to hql to be sent over the wire.
Is there another route I am missing?
I think I've seen ADO.NET Data Services as advertised to work with NHibernate:
http://wildermuth.com/2008/07/20/Silverlight_2_NHibernate_LINQ_==_Sweet
http://ayende.com/Blog/archive/2008/07/21/ADO.Net-Data-Services-with-NHibernate.aspx
This is an old post, and not sure how maintained this feature is, but its worth a shot.
I have a suggestion to you. Do not try to serialize query. Rather provide your user with an ability to compose arbitrary LINQ expression. Then send the expression over the wire (there is a gotcha here, since expressions are not serializable) to your server.
I have recently submitted to NHibernate.Linq project a change to their NHibernateExtensions class - a new ISession extension method List, which accepts an expression and fills the given list with the respective data, much like ICriteria.List method. The change was accepted (see here) so downloading the recent version of NHibernate.Linq should contain this method.
Anyway, you can find the details of this approach here.