Search code examples
javaspringsortingspring-dataspring-restcontroller

Prevent multiple sort parameters with Pageable in Spring REST Controllers


I'm working an API using Spring Boot and Spring Data repos (although not Spring Data REST).

@GetMapping
public List<Foo> listFoos(
    @SortDefault(value = "name", direction = Sort.Direction.ASC)
    Pageable pageable,
    HttpServletRequest request) {
  FooRepo.findAll(pageable);
}

The above works fine. I can sort fine by passing a sort parameter, however I'm a bit concerned about the performance implications.

I'd like to limit it to only support sort by a single parameter at a time for performance reasons. By default, I can do something like ?sort=name,createdAt which will generate a query to order by both name and createdAt. Given it's a public API, I'm a bit concerned about some users abusing this and attempting to sort by a whole bunch of values that we haven't optimised for.

Secondly, there are some values that don't make sense for sorting. For example, if Foo had a thumbnail URL, it wouldn't make sense to sort by thumbnail. Is there any ability to whitelist or blacklist the sort values?


Solution

  • you can make your CustomSortHandlerMethodArgumentResolver ( implements org.springframework.data.web.SortArgumentResolver spring implementation org.springframework.data.web.SortHandlerMethodArgumentResolver)

    @Configuration
    @EnableWebMvc
    public class WebMvcContext extends WebMvcConfigurerAdapter {
    
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            PageableArgumentResolverhandler = new PageableHandlerMethodArgumentResolver(
                    new CustomSortHandlerMethodArgumentResolver()); 
    
            argumentResolvers.add(handler);
        } 
    }
    

    in custom implementation, you can create white/black lists and customize the processing of the collation so as to you conveniently, and to avoid common mistakes - see the implementation of the spring

    one of the ways

    public class CustomSortHandlerMethodArgumentResolver extends 
            SortHandlerMethodArgumentResolver{
    
    
    
        @Override
        public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
            Sort sort = super.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    
            /*
                additional logic for filtering orders        
             */
    
            return sort != null && sort.iterator().hasNext() ? new Sort(sort.iterator().next()) : null;
        }
    }