Reputation: 563
As the title says.
I basically would love to do requests like
/api/todos/?completed=eq.true&created_at=lt.1486462109399
Is there any ready spring way
of achieving such? Something akin to the Page/Pageable mechanism would be great.
If there is none I think I could implement it using Hibernate Criteria Queries & Argument Re-solvers. Basically allowing me to write my controllers like
@GetMapping
public ResponseEntity<Page<TodoDTO>> listAll(Criteria criteria, Pageable pageable)
{
Page<Todo> todos = todoService.listAll(criteria, pageable)
...
}
A custom Argument resolver would be responsible for turning the query string into a Criteria. Not quite sure yet how I would handle it within the service but that's the direction in which I would try to implement this.
Would that be a good approach? Any recommendations? (All assuming there are no ready mechanism for such already).
Your help is much appreciated.
Upvotes: 27
Views: 42280
Reputation: 1
(Disclosure: I am owner of the linked repo)
This is another alternative to RQSL is the following library: https://github.com/RobertoMike/Baradum
It will let you run search queries such as:
/search?name=Pepito&age=18,65&active=true
This library supports custom functions, searching over nested fields, enums, strings, numbers, booleans, dates, ...
Very simple usage:
@GetMapping(value = "/search")
public List<Entity> search() {
return Baradum.make(User.class)
.allowedFilters(
// This allows you to filter using like and add automatically the % at the end of the value
// Example "?name=ale" will be filtered as "name like 'ale%'"
new PartialFilter("name"),
// This allows you to filter by range
new IntervalFilter<>("age"),
)
.get();
}
No need to configure anything, just import the dependency:
<dependency>
<groupId>io.github.robertomike</groupId>
<artifactId>baradum-apache-tomcat</artifactId>
<!-- For spring boot 2 -->
<version>1.0.1</version>
<!-- For spring boot 3 -->
<version>2.0.1</version>
</dependency>
Upvotes: 0
Reputation: 37916
Another option to build a fluent query API is to use a RSQL parser. RSQL is a query language for parametrized filtering of entries in RESTful APIs. Follow this article and your API would be able to handle URLs like:
http://localhost:8080/users?search=firstName==jo*;age<25
Sample controller:
@RestController
@RequestMapping(value = "/users")
public class UserController {
@Autowired
private UserRepository repo;
@GetMapping
public List<User> findAllByRsql(@RequestParam(value = "search") String search) {
Node rootNode = new RSQLParser().parse(search);
Specification<User> spec = rootNode.accept(new CustomRsqlVisitor<User>());
return repo.findAll(spec);
}
}
Gradle dependency:
// https://mvnrepository.com/artifact/cz.jirutka.rsql/rsql-parser
implementation("cz.jirutka.rsql:rsql-parser:2.1.0")
Recommendations from the library author:
I recommend to use separate URI query parameter for sorting, e.g.
?query=name==Flynn&sortBy=name
, not to mix it with RSQL expression. The same applies to paging; I recommend URI parameters namedlimit
andoffset
.
Upvotes: 14
Reputation: 167
As a good alternative to RQSL, you may use the following library: https://github.com/turkraft/spring-filter
It will let you run search queries such as:
/search?filter= average(ratings) > 4.5 and brand.name in ('audi', 'land rover') and (year > 2018 or km < 50000) and color : 'white' and accidents is empty
As you see in the example, it supports functions, searching over nested fields, nested logics, enums, strings, numbers, booleans, dates, ...
Very simple usage:
@GetMapping(value = "/search")
public Page<Entity> search(@Filter Specification<Entity> spec, Pageable page) {
return repo.findAll(spec, page);
}
No need to configure anything, just import the dependency:
<dependency>
<groupId>com.turkraft</groupId>
<artifactId>spring-filter</artifactId>
<version>1.0.5</version>
</dependency>
There are also examples using MongoDB.
Upvotes: 5
Reputation: 7230
You may also want to try Spring Search: https://github.com/sipios/spring-search
Example: /cars?search=creationyear:2018 AND price<300000 AND (color:Yellow OR color:Blue) AND options.transmission:Auto
Upvotes: 5
Reputation: 37916
You can build a Search/Filter REST API using Spring Data JPA and Specifications. Here is a test URL example that the resulting API would be able to handle:
http://localhost:8080/users?search=lastName:doe,age>25
and example controller:
@RestController
@RequestMapping(value = "/users")
public class UserController {
@Autowired
private UserRepository repo;
@GetMapping
public List<User> search(@RequestParam(value = "search") String search) {
UserSpecificationsBuilder builder = new UserSpecificationsBuilder();
Pattern pattern = Pattern.compile("(\w+?)(:|<|>)(\w+?),");
Matcher matcher = pattern.matcher(search + ",");
while (matcher.find()) {
builder.with(matcher.group(1), matcher.group(2), matcher.group(3));
}
Specification<User> spec = builder.build();
return repo.findAll(spec);
}
}
Upvotes: 10