Search code examples
javarestspring-bootspring-data-jpasoftware-design

How would you handle a REST API with only optional query params with Spring Boot?


I want to build a simple endpoint that returns an Order object where I can search for this order by a single query parameter or a combination of several query parameters altogether. All of these query parameters are optional and the reason is that different people will access these orders based on the different Ids.

So for example: /order/items?itemId={itemId}&orderId={orderId}&deliveryId={deliveryId}&packetId={packetId}

@GetMapping(path = "/order/items", produces = "application/json")
public Order getOrders(@RequestParam Optional<String> itemId,
                              @RequestParam Optional<String> orderId,
                              @RequestParam Optional<String> deliveryId,
                              @RequestParam Optional<String> packetId) { }

I could of course also skip the Java Optional and use @RequestParam(required = false), but the question here is rather how do I escape the if-else or .isPresent() nightmare of checking whether the query params are null? Or is there an elegant way, depending on the constellation of params, to pass further to my service and Spring Data JPA repository.


Solution

  • To minimize the amount of parameters in your method, you could define your query parameters as fields of a class:

    @Data
    public class SearchOrderCriteria {
        private String itemId;
        private String orderId;
        private String deliveryId;
        private String packetId;
    }
    

    Then receive an instance of such class in your controller method:

    @GetMapping(path = "/order/items", produces = "application/json")
    public ResponseEntity<OrderInfo> getOrder(SearchOrderCriteria searchCriteria) {
        OrderInfo order = orderService.findOrder(searchCriteria)
        return ResponseEntity.ok(order);
    }
    

    And, in your service, to avoid a bunch of if-else, you could use query by example:

    public OrderInfo findOrder(SearchOrderCriteria searchCriteria) {
    
        OrderInfo order = new OrderInfo();
        order.setItemId(searchCriteria.getItemId());
        order.setOrderId(searchCriteria.getOrderId());
        order.setDeliveryId(searchCriteria.getDeliveryId());
        order.setPacketId(searchCriteria.getPacketId());
    
        Example<OrderInfo> example = Example.of(order);
        return orderRepository.findOne(example);
    }