Issue
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)
Solution
create one endpoint with Your custom filter object containing filter fields and then build Specification
using that filter, then query database using that Specification
Answered By - lukwas
Answer Checked By - David Marino (JavaFixing Volunteer)