0

I am implementing a product search feature where user can search for products based on name, brand, and price. I have written different endpoints for searching for different combination and I hate the code and I cannot add additional filters easily and have to create all the combination for any additional filter I have to add.

My Product Repository -

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.vaibhavshrivastava.productbrowser.model.Product;

public interface ProductRepository extends JpaRepository<Product, Integer> {
//  
    public List<Product> findByName(String name);
    public List<Product> findByNameAndProductCode(String name, int productCode);
    public List<Product> findByNameAndBrand(String name, String brand);
    public List<Product> findByNameAndBrandAndProductCode(String name, String brand, int productCode);
    public List<Product> findByBrand(String brand);
    public List<Product> findByProductCode(int productCode);
    public List<Product> findByBrandAndProductCode(String brand, int productCode);
//  public int getPrice(int productCode);
    public Optional<Product> findByProductCode(Integer productCode);

}

My Product Controller -

@RestController
@CrossOrigin
@RequestMapping("/products")
public class ProductController {

    @Autowired
    ProductRepository productRepository;
    
    @Autowired
    ProductService productService;

    @GetMapping("/nameandbrand")
    public ResponseEntity<List<Product>> getProductsByNameAndBrand(@RequestParam String name,
            @RequestParam String brand) {
        return new ResponseEntity<>(productRepository.findByNameAndBrand(name, brand), HttpStatus.OK);
    }

    @GetMapping("/nameandproductcode")
    public ResponseEntity<List<Product>> getProductsByNameAndProductCode(@RequestParam String name,
            @RequestParam int productCode) {
        return new ResponseEntity<>(productRepository.findByNameAndProductCode(name, productCode), HttpStatus.OK);
    }

    @GetMapping("/name")
    public ResponseEntity<List<Product>> getProductsByName(@RequestParam String name) {
        return new ResponseEntity<>(productRepository.findByName(name), HttpStatus.OK);
    }
    
    @GetMapping("/nameandbrandandproductcode")
    public ResponseEntity<List<Product>> getProductsByNameOrBrandOrProductCode(@RequestParam String name, @RequestParam String brand, @RequestParam int productCode){
        return new ResponseEntity<>(productRepository.findByNameAndBrandAndProductCode(name, brand, productCode), HttpStatus.OK);
    }
    
    @GetMapping("/brand")
    public ResponseEntity<List<Product>> getProductsByBrand(@RequestParam String brand){
        return new ResponseEntity<>(productRepository.findByBrand(brand), HttpStatus.OK);
    }
    
    @GetMapping(name="/productcode")
    public ResponseEntity<Optional<Product>> getProductsByProductCode(@RequestParam Integer productCode){
        return new ResponseEntity<>(productRepository.findByProductCode(productCode), HttpStatus.OK);
    }
    
    @GetMapping("/brandandproductcode")
    public ResponseEntity<List<Product>> getProductsByBrandAndProductCode(@RequestParam String brand, @RequestParam int productCode){
        return new ResponseEntity<>(productRepository.findByBrandAndProductCode(brand, productCode), HttpStatus.OK);
    }
    
    @GetMapping("/{pid}/details")
    public ResponseEntity<Product> getProductDetails(@PathVariable("pid") Integer productCode){
        System.out.println("PPPPPPPPPPRDDDDDDDCTTTT CODEEEEE" + productCode);
        Product selectedProduct = productRepository.findByProductCode(productCode).orElseThrow();
        return new ResponseEntity<>(selectedProduct, HttpStatus.OK);
    }
    
    @GetMapping("/")
    public List<Product> getProducts(){
        return productService.getProducts();
    }
    
}

I have not yet added the Price filter and I have to add it so I have to make all the combinations to search with price filter too. What is the best way to implement something like this?

I am sending parameters using angular on the frontend.

How to transform this bad code into something in which I can add additional filters easily.

My Product Entity have these fields -

@Entity
public class Product {

    @Id
    private int productCode;

    private String name;
    private String brand;
    private String description;
    private int price;
    private String img;

(Not included hash and getters and setters etc)

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Innomight
  • 556
  • 3
  • 15

1 Answers1

3

create one endpoint with Your custom filter object containing filter fields and then build Specification using that filter, then query database using that Specification

lukwas
  • 232
  • 1
  • 2
  • 11
  • specification is exactly what he need – Zhiqiang Guo Oct 17 '22 at 07:27
  • You mean, use if-else in /search api endpoint like if (name="", brand="samsung"){findByNameAndBrand} ? Still, I have to create combinations for all if-else statements right? – Innomight Oct 17 '22 at 07:28
  • 1
    no if-else one simple endpoint `@RequestMapping public ResponseEntity filter(SearchFilter filter, Pageable pageable) {` and map `filter` to `Specification` see here: https://www.baeldung.com/rest-api-search-language-spring-data-specifications – lukwas Oct 17 '22 at 07:55