From f2d62f6c7037644611d40849a2f73bdbdfb1104b Mon Sep 17 00:00:00 2001 From: Eren Date: Sun, 19 Apr 2026 19:23:02 +0200 Subject: [PATCH 1/6] UpdateV1 --- .../Controllers/CustomerController.java | 4 + .../Controllers/ProductController.java | 91 ++++++++++++++++++ .../com/SpringRestAPI/Models/Customer.java | 67 +++++++++++++ .../com/SpringRestAPI/Models/Product.java | 78 +++++++++++++++ .../Models/ProductCategories.java | 7 ++ .../Services/CustomerService.java | 58 +++++++++++ .../Services/ProductService.java | 96 +++++++++++++++++++ .../SpringBootRestApiApplication.java | 13 +++ src/main/resources/application.properties | 1 + .../SpringBootRestApiApplicationTests.java | 13 +++ 10 files changed, 428 insertions(+) create mode 100644 src/main/java/com/SpringRestAPI/Controllers/CustomerController.java create mode 100644 src/main/java/com/SpringRestAPI/Controllers/ProductController.java create mode 100644 src/main/java/com/SpringRestAPI/Models/Customer.java create mode 100644 src/main/java/com/SpringRestAPI/Models/Product.java create mode 100644 src/main/java/com/SpringRestAPI/Models/ProductCategories.java create mode 100644 src/main/java/com/SpringRestAPI/Services/CustomerService.java create mode 100644 src/main/java/com/SpringRestAPI/Services/ProductService.java create mode 100644 src/main/java/com/SpringRestAPI/SpringBootRestApiApplication.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/com/SpringRestAPI/SpringBootRestApiApplicationTests.java diff --git a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java new file mode 100644 index 0000000..0cce375 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java @@ -0,0 +1,4 @@ +package com.SpringRestAPI.Controllers; + +public class CustomerController { +} diff --git a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java new file mode 100644 index 0000000..5883fc1 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java @@ -0,0 +1,91 @@ +package com.SpringRestAPI.Controllers; + +import com.SpringRestAPI.Models.Product; +import com.SpringRestAPI.Models.ProductCategories; +import com.SpringRestAPI.Services.ProductService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.logging.Logger; + +@RestController +@RequestMapping("/api") +public class ProductController { + + + ProductService productService; + + public ProductController(ProductService productService) { + this.productService = productService; + } + + // Create new product + @PostMapping("/products/{productName}/{productPrice}/{productCategory}/{productQuantity}") // http://localhost:8080/api/products/ + public boolean addNewProduct(@PathVariable String productName, @PathVariable double productPrice, @PathVariable ProductCategories productCategory, @PathVariable int productQuantity) { + Logger myLogger = Logger.getLogger("ProductController"); + myLogger.info("Create a new Product"); + + return productService.addNewProduct(productName, productPrice, productCategory, productQuantity); + } + + // get all products + @GetMapping("/products") // http://localhost:8080/api/products/ + public List getAllProducts() { + Logger myLogger = Logger.getLogger("ProductList"); + myLogger.info("Get all the Product list"); + + return productService.getProductList(); + } + + // get all products by name + @GetMapping("/products/{productName}") // http://localhost:8080/api/products/{name} + public List getProductByname(@PathVariable String productName) { + Logger myLogger = Logger.getLogger("ProductList by Name"); + myLogger.info("Get Product list by Name"); + + return productService.getProductByName(productName); + } + + // change product name TODO + @PutMapping("/products/{productName}/{newName}") // http://localhost:8080/api/products/{name}/{newName} + public Product getProductByName(@PathVariable String productName, @PathVariable String newName) { + Logger myLogger = Logger.getLogger(" by Name"); + myLogger.info("change Product Name"); + + return productService.updateProductName(productName, newName); + } + + // delete product by name + @DeleteMapping("/products/{productName}") // http://localhost:8080/api/products/{productName} + public List deleteProduct(@PathVariable String productName) { + Logger myLogger = Logger.getLogger("ProductList by Name"); + myLogger.info("delete Product by Name"); + + return productService.deleteProduct(productName); + } + + // get item by category + @GetMapping("/products/category/{category}") // http://localhost:8080/api/products/category/{category} + public List getProductByCategory(@PathVariable ProductCategories category) { + Logger myLogger = Logger.getLogger("ProductList by Category"); + myLogger.info("get Product by Category"); + + return productService.getProductByCategory(category); + } + + // get products by price range + @GetMapping("/products/price/min{minPrice}/max{maxPrice}") + public List getProductsByPriceRange(@PathVariable Double minPrice, @PathVariable Double maxPrice) { + Logger myLogger = Logger.getLogger("ProductList by Price range"); + myLogger.info("get Product by Price range"); + + return productService.getProductsByPriceRange(minPrice, maxPrice); + } + + + + + + + +} diff --git a/src/main/java/com/SpringRestAPI/Models/Customer.java b/src/main/java/com/SpringRestAPI/Models/Customer.java new file mode 100644 index 0000000..df2d698 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Models/Customer.java @@ -0,0 +1,67 @@ +package com.SpringRestAPI.Models; + +public class Customer { + + private String customerName; + private String customerEmail; + private int customerAge; + private String customerAddress; + + public Customer(String customerName, String customerEmail, int customerAge, String customerAddress) { + this.customerName = customerName; + this.customerEmail = customerEmail; + this.customerAge = customerAge; + this.customerAddress = customerAddress; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName() { + if (customerName.isEmpty()) { + System.out.println("Customer name is cannot be empty"); + } + else { + this.customerName = customerName; + } + } + + public String getCustomerEmail() { + return customerEmail; + } + + public void setCustomerEmail(String customerEmail) { + if (!customerEmail.contains("@") || + !customerEmail.contains(".") || + customerEmail.contains(" ")) { + System.out.println("Customer email is invalid"); + } else { + this.customerEmail = customerEmail; + } + } + + public int getCustomerAge() { + return customerAge; + } + + public void setCustomerAge(int customerAge) { + if (customerAge < 18) { + System.out.println("Sorry, you must be at least 18!"); + } else { + this.customerAge = customerAge; + } + } + + public String getCustomerAddress() { + return customerAddress; + } + + public void setCustomerAddress(String customerAddress) { + if (customerAddress.isEmpty()) { + System.out.println("Customer address is cannot be empty"); + } else { + this.customerAddress = customerAddress; + } + } +} diff --git a/src/main/java/com/SpringRestAPI/Models/Product.java b/src/main/java/com/SpringRestAPI/Models/Product.java new file mode 100644 index 0000000..0cffcce --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Models/Product.java @@ -0,0 +1,78 @@ +package com.SpringRestAPI.Models; + +public class Product { + + String productName; + double productPrice; + ProductCategories productCategory; + int productQuantity; + + public Product(String productName, double productPrice, ProductCategories productCategory, int productQuantity) { + this.productName = productName; + this.productPrice = productPrice; + this.productCategory = productCategory; + this.productQuantity = productQuantity; + } + + public String getProductName() { + return productName; + } + + public void setProductName() { + if (productName.length() >= 3) { + this.productName = productName; + } + else { + System.out.println("Product name must contain at least 3 characters."); + } + } + + public double getProductPrice() { + return productPrice; + } + + public void setProductPrice(double productPrice) { + if (productPrice >= 0) { + this.productPrice = productPrice; + } + else { + System.out.println("Product price cannot be negative."); + } + } + + public ProductCategories getProductCategory() { + return productCategory; + } + + public void setProductCategory(ProductCategories productCategory) { + if (productCategory != null) { + this.productCategory = productCategory; + } + else { + System.out.println("Product category cannot be empty."); + } + } + + public int getProductQuantity() { + return productQuantity; + } + + public void setProductQuantity(int productQuantity) { + if (productQuantity >= 0) { + this.productQuantity = productQuantity; + } + else { + System.out.println("Product quantity cannot be negative."); + } + } + + @Override + public String toString() { + return "Product{" + + "productName='" + productName + '\'' + + ", productPrice=" + productPrice + + ", productCategory=" + productCategory + + ", productQuantity=" + productQuantity + + '}'; + } +} diff --git a/src/main/java/com/SpringRestAPI/Models/ProductCategories.java b/src/main/java/com/SpringRestAPI/Models/ProductCategories.java new file mode 100644 index 0000000..9ab208d --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Models/ProductCategories.java @@ -0,0 +1,7 @@ +package com.SpringRestAPI.Models; + +public enum ProductCategories { + + ELECTRONIC, TOYS, MUSIC, MOVIE, BOOKS + +} diff --git a/src/main/java/com/SpringRestAPI/Services/CustomerService.java b/src/main/java/com/SpringRestAPI/Services/CustomerService.java new file mode 100644 index 0000000..12bb19d --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Services/CustomerService.java @@ -0,0 +1,58 @@ +package com.SpringRestAPI.Services; + +import com.SpringRestAPI.Models.Customer; +import com.SpringRestAPI.Models.Product; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class CustomerService { + + private List customers; + + public CustomerService() { + setCustomerList(); + } + + // creating customers + public void setCustomerList() { + customers = new ArrayList<>(); + + customers.add(new Customer("Eren", "eren@test.com", 20, "Hamburg, Germany")); + customers.add(new Customer("Mikasa", "mikasa@test.com", 20, "Berlin, Germany")); + customers.add(new Customer("Armin", "armin@test.com", 20, "Leipzig, Germany")); + } + + // get all customers + public List getCustomers() { + return customers; + } + + // get customer by email + public List getCustomerByEmail(String email) { + List customerList = new ArrayList<>(); + for (Customer customer : customers) { + if (customer.getCustomerEmail().equals(email)) { + customerList.add(customer); + } + } + return customerList; + } + + // update customer + public Customer updateCustomerName(String currentName, String newName) { + for (Customer customer : customers) { + if (customer.getCustomerName().equalsIgnoreCase(currentName)) { + customer.setCustomerName(); + return customer; + } + } + throw new RuntimeException("Product not found"); + } + + + + +} diff --git a/src/main/java/com/SpringRestAPI/Services/ProductService.java b/src/main/java/com/SpringRestAPI/Services/ProductService.java new file mode 100644 index 0000000..35e9ffc --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Services/ProductService.java @@ -0,0 +1,96 @@ +package com.SpringRestAPI.Services; + +import com.SpringRestAPI.Models.Product; +import com.SpringRestAPI.Models.ProductCategories; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ProductService { + + private List productList; + + public ProductService() { + setProductList(); + } + + public void setProductList (){ + productList = new ArrayList<>(); + + productList.add(new Product("iPhone 17",879.00, ProductCategories.ELECTRONIC,5)); + productList.add(new Product("Hot Wheels Porsche",4.99, ProductCategories.TOYS,20)); + productList.add(new Product("Ado's Best Adobum",39.00, ProductCategories.MUSIC,3)); + productList.add(new Product("Howl's Moving Castle",27.50, ProductCategories.MOVIE,50)); + productList.add(new Product("The Hunger Games",19.90, ProductCategories.BOOKS,110)); + } + + // add a new product + public boolean addNewProduct(String productName, double productPrice, ProductCategories productCategory, int productQuantity) { + productList.add(new Product(productName, productPrice, productCategory, productQuantity)); + return true; + } + + // get all products + public List getProductList() { + return productList; + } + + // get products by name + public List getProductByName(String productName) { + List products = new ArrayList<>(); + for (Product product : productList) { + if (product.getProductName().equals(productName)) { + products.add(product); + } + } + return products; + } + + // update product + public Product updateProductName(String currentName, String newName) { + for (Product product : productList) { + if (product.getProductName().equalsIgnoreCase(currentName)) { + product.setProductName(); + return product; + } + } + throw new RuntimeException("Product not found"); + } + + // delete product + public List deleteProduct (String productName){ + for (Product product : productList) { + if (product.getProductName().equals(productName)) { + productList.remove(product); + } + } + return productList; + } + + // get products by category + public List getProductByCategory (ProductCategories productCategory){ + List products = new ArrayList<>(); + for (Product product : productList) { + if (product.getProductCategory().equals(productCategory)) { + products.add(product); + } + } + return products; + } + + // get products by price range + public List getProductsByPriceRange (double minPrice, double maxPrice){ + List products = new ArrayList<>(); + for (Product product : productList) { + if (product.getProductPrice()>=minPrice&&product.getProductPrice()<=maxPrice) { + products.add(product); + } + } + return products; + } + +} diff --git a/src/main/java/com/SpringRestAPI/SpringBootRestApiApplication.java b/src/main/java/com/SpringRestAPI/SpringBootRestApiApplication.java new file mode 100644 index 0000000..4d16643 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/SpringBootRestApiApplication.java @@ -0,0 +1,13 @@ +package com.SpringRestAPI; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootRestApiApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootRestApiApplication.class, args); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..403d95f --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=SpringBoot-REST-API diff --git a/src/test/java/com/SpringRestAPI/SpringBootRestApiApplicationTests.java b/src/test/java/com/SpringRestAPI/SpringBootRestApiApplicationTests.java new file mode 100644 index 0000000..abd5fdd --- /dev/null +++ b/src/test/java/com/SpringRestAPI/SpringBootRestApiApplicationTests.java @@ -0,0 +1,13 @@ +package com.SpringRestAPI; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringBootRestApiApplicationTests { + + @Test + void contextLoads() { + } + +} From 731c7b80456a159cca815723b5bf4c9ba5cebbfb Mon Sep 17 00:00:00 2001 From: Eren Date: Sun, 19 Apr 2026 20:48:30 +0200 Subject: [PATCH 2/6] UpdateV2 --- .../Controllers/CustomerController.java | 66 +++++++++++++++++++ .../Controllers/ProductController.java | 4 +- .../com/SpringRestAPI/Models/Customer.java | 27 +++++--- .../com/SpringRestAPI/Models/Product.java | 16 ++--- .../Services/CustomerService.java | 25 +++++-- .../Services/ProductService.java | 13 ++-- 6 files changed, 121 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java index 0cce375..c5b6fdc 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java @@ -1,4 +1,70 @@ package com.SpringRestAPI.Controllers; + +import com.SpringRestAPI.Models.Customer; +import com.SpringRestAPI.Services.CustomerService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.logging.Logger; + +@RestController +@RequestMapping("/api") public class CustomerController { + + CustomerService customerService; + + public CustomerController(CustomerService customerService) { + this.customerService = customerService; + } + + // create new customer + @PostMapping("/customer/{customerName}/{customerEmail}/{customerAge}/{customerAddress}") + public String addNewCustomer(@PathVariable String customerName, @PathVariable String customerEmail,@PathVariable int customerAge, @PathVariable String customerAddress ) { + Logger myLogger = Logger.getLogger("CustomerController new customer"); + myLogger.info("Adding new customer "); + + return customerService.addNewCustomer(customerName, customerEmail, customerAge, customerAddress); + + } + + // get all customer + @GetMapping("/customer") + public List getCustomers() { + Logger myLogger = Logger.getLogger("CustomerService get all customers"); + myLogger.info("Getting all customers"); + + return customerService.getCustomers(); + } + + // get customer by email + @GetMapping("/customer/{customerEmail}") + public List getCustomers(@PathVariable String customerEmail) { + Logger myLogger = Logger.getLogger("CustomerService getting customer by email"); + myLogger.info("Getting customer by email"); + + return customerService.getCustomerByEmail(customerEmail); + } + + // update customer name + @PutMapping("/customer/{currentName}/{newName}") + public Customer updateCustomerName(@PathVariable String currentName, @PathVariable String newName) { + Logger myLogger = Logger.getLogger("CustomerController update customer name"); + myLogger.info("Updating customer name"); + + return customerService.updateCustomerName(currentName, newName); + } + + // delete customer + @DeleteMapping("/customer/{customerName}") + public List deleteCustomer(@PathVariable String customerName) { + Logger myLogger = Logger.getLogger("CustomerController delete customer name"); + myLogger.info("Deleting customer name"); + + return customerService.deleteCustomer(customerName); + } + + + + } diff --git a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java index 5883fc1..84617a9 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java @@ -21,7 +21,7 @@ public ProductController(ProductService productService) { // Create new product @PostMapping("/products/{productName}/{productPrice}/{productCategory}/{productQuantity}") // http://localhost:8080/api/products/ - public boolean addNewProduct(@PathVariable String productName, @PathVariable double productPrice, @PathVariable ProductCategories productCategory, @PathVariable int productQuantity) { + public Product addNewProduct(@PathVariable String productName, @PathVariable double productPrice, @PathVariable ProductCategories productCategory, @PathVariable int productQuantity) { Logger myLogger = Logger.getLogger("ProductController"); myLogger.info("Create a new Product"); @@ -46,7 +46,7 @@ public List getProductByname(@PathVariable String productName) { return productService.getProductByName(productName); } - // change product name TODO + // change product name @PutMapping("/products/{productName}/{newName}") // http://localhost:8080/api/products/{name}/{newName} public Product getProductByName(@PathVariable String productName, @PathVariable String newName) { Logger myLogger = Logger.getLogger(" by Name"); diff --git a/src/main/java/com/SpringRestAPI/Models/Customer.java b/src/main/java/com/SpringRestAPI/Models/Customer.java index df2d698..9c2fde7 100644 --- a/src/main/java/com/SpringRestAPI/Models/Customer.java +++ b/src/main/java/com/SpringRestAPI/Models/Customer.java @@ -18,9 +18,9 @@ public String getCustomerName() { return customerName; } - public void setCustomerName() { - if (customerName.isEmpty()) { - System.out.println("Customer name is cannot be empty"); + public void setCustomerName(String customerName) { + if (customerName == null || customerName.trim().isEmpty()) { + throw new IllegalArgumentException("Customer name is cannot be empty"); } else { this.customerName = customerName; @@ -32,10 +32,11 @@ public String getCustomerEmail() { } public void setCustomerEmail(String customerEmail) { - if (!customerEmail.contains("@") || + if (customerEmail == null || + !customerEmail.contains("@") || !customerEmail.contains(".") || customerEmail.contains(" ")) { - System.out.println("Customer email is invalid"); + throw new IllegalArgumentException("Customer email is invalid"); } else { this.customerEmail = customerEmail; } @@ -47,7 +48,7 @@ public int getCustomerAge() { public void setCustomerAge(int customerAge) { if (customerAge < 18) { - System.out.println("Sorry, you must be at least 18!"); + throw new IllegalArgumentException("Sorry, you must be at least 18!"); } else { this.customerAge = customerAge; } @@ -58,10 +59,20 @@ public String getCustomerAddress() { } public void setCustomerAddress(String customerAddress) { - if (customerAddress.isEmpty()) { - System.out.println("Customer address is cannot be empty"); + if (customerAddress == null || customerAddress.trim().isEmpty()) { + throw new IllegalArgumentException("Customer address is cannot be empty"); } else { this.customerAddress = customerAddress; } } + + @Override + public String toString() { + return "Customer{" + + "customerName='" + customerName + '\'' + + ", customerEmail='" + customerEmail + '\'' + + ", customerAge=" + customerAge + + ", customerAddress='" + customerAddress + '\'' + + '}'; + } } diff --git a/src/main/java/com/SpringRestAPI/Models/Product.java b/src/main/java/com/SpringRestAPI/Models/Product.java index 0cffcce..186cea3 100644 --- a/src/main/java/com/SpringRestAPI/Models/Product.java +++ b/src/main/java/com/SpringRestAPI/Models/Product.java @@ -18,12 +18,12 @@ public String getProductName() { return productName; } - public void setProductName() { - if (productName.length() >= 3) { + public void setProductName(String productName) { + if (productName !=null && productName.trim().length() >= 3) { this.productName = productName; } else { - System.out.println("Product name must contain at least 3 characters."); + throw new IllegalArgumentException("Product name must contain at least 3 characters."); } } @@ -32,11 +32,11 @@ public double getProductPrice() { } public void setProductPrice(double productPrice) { - if (productPrice >= 0) { + if (productPrice > 0) { this.productPrice = productPrice; } else { - System.out.println("Product price cannot be negative."); + throw new IllegalArgumentException("Product price cannot be negative."); } } @@ -49,7 +49,7 @@ public void setProductCategory(ProductCategories productCategory) { this.productCategory = productCategory; } else { - System.out.println("Product category cannot be empty."); + throw new IllegalArgumentException("Product category cannot be empty."); } } @@ -58,11 +58,11 @@ public int getProductQuantity() { } public void setProductQuantity(int productQuantity) { - if (productQuantity >= 0) { + if (productQuantity > 0) { this.productQuantity = productQuantity; } else { - System.out.println("Product quantity cannot be negative."); + throw new IllegalArgumentException("Product quantity cannot be negative."); } } diff --git a/src/main/java/com/SpringRestAPI/Services/CustomerService.java b/src/main/java/com/SpringRestAPI/Services/CustomerService.java index 12bb19d..d8aad9e 100644 --- a/src/main/java/com/SpringRestAPI/Services/CustomerService.java +++ b/src/main/java/com/SpringRestAPI/Services/CustomerService.java @@ -1,9 +1,7 @@ package com.SpringRestAPI.Services; import com.SpringRestAPI.Models.Customer; -import com.SpringRestAPI.Models.Product; import org.springframework.stereotype.Service; - import java.util.ArrayList; import java.util.List; @@ -30,11 +28,17 @@ public List getCustomers() { return customers; } + // add new customer + public String addNewCustomer(String customerName, String customerEmail, int customerAge, String customerAddress) { + customers.add(new Customer(customerName, customerEmail, customerAge, customerAddress)); + return "new customer added"; + } + // get customer by email public List getCustomerByEmail(String email) { List customerList = new ArrayList<>(); for (Customer customer : customers) { - if (customer.getCustomerEmail().equals(email)) { + if (customer.getCustomerEmail().equalsIgnoreCase(email)) { customerList.add(customer); } } @@ -45,14 +49,25 @@ public List getCustomerByEmail(String email) { public Customer updateCustomerName(String currentName, String newName) { for (Customer customer : customers) { if (customer.getCustomerName().equalsIgnoreCase(currentName)) { - customer.setCustomerName(); + customer.setCustomerName(newName); return customer; } } - throw new RuntimeException("Product not found"); + throw new RuntimeException("Customer not found"); + } + + // delete customer + public List deleteCustomer (String customerName){ + for (Customer customer : customers) { + if (customer.getCustomerName().equals(customerName)) { + customers.remove(customer); + } + } + return customers; } + } diff --git a/src/main/java/com/SpringRestAPI/Services/ProductService.java b/src/main/java/com/SpringRestAPI/Services/ProductService.java index 35e9ffc..52d3d91 100644 --- a/src/main/java/com/SpringRestAPI/Services/ProductService.java +++ b/src/main/java/com/SpringRestAPI/Services/ProductService.java @@ -5,9 +5,7 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; @Service public class ProductService { @@ -29,9 +27,10 @@ public void setProductList (){ } // add a new product - public boolean addNewProduct(String productName, double productPrice, ProductCategories productCategory, int productQuantity) { - productList.add(new Product(productName, productPrice, productCategory, productQuantity)); - return true; + public Product addNewProduct(String productName, double productPrice, ProductCategories productCategory, int productQuantity) { + Product newProduct = new Product(productName, productPrice, productCategory, productQuantity); + productList.add(newProduct); + return newProduct; } // get all products @@ -43,7 +42,7 @@ public List getProductList() { public List getProductByName(String productName) { List products = new ArrayList<>(); for (Product product : productList) { - if (product.getProductName().equals(productName)) { + if (product.getProductName().equalsIgnoreCase(productName)) { products.add(product); } } @@ -54,7 +53,7 @@ public List getProductByName(String productName) { public Product updateProductName(String currentName, String newName) { for (Product product : productList) { if (product.getProductName().equalsIgnoreCase(currentName)) { - product.setProductName(); + product.setProductName(newName); return product; } } From a73924b512abdaa46478546850984c316213215d Mon Sep 17 00:00:00 2001 From: Eren Date: Sun, 19 Apr 2026 21:45:14 +0200 Subject: [PATCH 3/6] UpdateV3 --- .../Controllers/CustomerController.java | 12 ++-- .../Controllers/ProductController.java | 68 ++++++++++++++----- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java index c5b6fdc..e0a83df 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java @@ -19,13 +19,17 @@ public CustomerController(CustomerService customerService) { } // create new customer - @PostMapping("/customer/{customerName}/{customerEmail}/{customerAge}/{customerAddress}") - public String addNewCustomer(@PathVariable String customerName, @PathVariable String customerEmail,@PathVariable int customerAge, @PathVariable String customerAddress ) { + @PostMapping("/customer") + public String addNewCustomer(@RequestBody Customer customer ) { Logger myLogger = Logger.getLogger("CustomerController new customer"); myLogger.info("Adding new customer "); - return customerService.addNewCustomer(customerName, customerEmail, customerAge, customerAddress); - + return customerService.addNewCustomer( + customer.getCustomerName(), + customer.getCustomerEmail(), + customer.getCustomerAge(), + customer.getCustomerAddress() + ); } // get all customer diff --git a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java index 84617a9..b3a3012 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java @@ -20,17 +20,31 @@ public ProductController(ProductService productService) { } // Create new product - @PostMapping("/products/{productName}/{productPrice}/{productCategory}/{productQuantity}") // http://localhost:8080/api/products/ - public Product addNewProduct(@PathVariable String productName, @PathVariable double productPrice, @PathVariable ProductCategories productCategory, @PathVariable int productQuantity) { + @PostMapping("/products") // http://localhost:8080/api/products/ + public Product addNewProduct( + @RequestHeader("API-Key") String apiKey, + @RequestBody Product product + ) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductController"); myLogger.info("Create a new Product"); - return productService.addNewProduct(productName, productPrice, productCategory, productQuantity); + return productService.addNewProduct( + product.getProductName(), + product.getProductPrice(), + product.getProductCategory(), + product.getProductQuantity() + ); } // get all products @GetMapping("/products") // http://localhost:8080/api/products/ - public List getAllProducts() { + public List getAllProducts(@RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductList"); myLogger.info("Get all the Product list"); @@ -39,7 +53,12 @@ public List getAllProducts() { // get all products by name @GetMapping("/products/{productName}") // http://localhost:8080/api/products/{name} - public List getProductByname(@PathVariable String productName) { + public List getProductByName( + @RequestHeader("API-Key") String apiKey, + @PathVariable String productName) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductList by Name"); myLogger.info("Get Product list by Name"); @@ -48,7 +67,13 @@ public List getProductByname(@PathVariable String productName) { // change product name @PutMapping("/products/{productName}/{newName}") // http://localhost:8080/api/products/{name}/{newName} - public Product getProductByName(@PathVariable String productName, @PathVariable String newName) { + public Product updateProductName( + @PathVariable String productName, + @PathVariable String newName, + @RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger(" by Name"); myLogger.info("change Product Name"); @@ -57,7 +82,12 @@ public Product getProductByName(@PathVariable String productName, @PathVariable // delete product by name @DeleteMapping("/products/{productName}") // http://localhost:8080/api/products/{productName} - public List deleteProduct(@PathVariable String productName) { + public List deleteProduct( + @PathVariable String productName, + @RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductList by Name"); myLogger.info("delete Product by Name"); @@ -66,7 +96,12 @@ public List deleteProduct(@PathVariable String productName) { // get item by category @GetMapping("/products/category/{category}") // http://localhost:8080/api/products/category/{category} - public List getProductByCategory(@PathVariable ProductCategories category) { + public List getProductByCategory( + @PathVariable ProductCategories category, + @RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductList by Category"); myLogger.info("get Product by Category"); @@ -74,18 +109,17 @@ public List getProductByCategory(@PathVariable ProductCategories catego } // get products by price range - @GetMapping("/products/price/min{minPrice}/max{maxPrice}") - public List getProductsByPriceRange(@PathVariable Double minPrice, @PathVariable Double maxPrice) { + @GetMapping("/products/price") + public List getProductsByPriceRange( + @RequestParam double minPrice, + @RequestParam double maxPrice, + @RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } Logger myLogger = Logger.getLogger("ProductList by Price range"); myLogger.info("get Product by Price range"); return productService.getProductsByPriceRange(minPrice, maxPrice); } - - - - - - - } From e8fe5096f00199327d6df47270212b22b3ee8607 Mon Sep 17 00:00:00 2001 From: Eren Date: Sun, 19 Apr 2026 22:20:22 +0200 Subject: [PATCH 4/6] UpdateFinal --- .../Controllers/CustomerController.java | 47 +++++++++--- .../Controllers/ProductController.java | 72 +++++++++++++------ .../InvalidPriceRangeException.java | 7 ++ .../Exceptions/MissingApiKeyException.java | 7 ++ .../Exceptions/ProductNotFoundException.java | 7 ++ .../Services/ProductService.java | 4 +- 6 files changed, 109 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/SpringRestAPI/Exceptions/InvalidPriceRangeException.java create mode 100644 src/main/java/com/SpringRestAPI/Exceptions/MissingApiKeyException.java create mode 100644 src/main/java/com/SpringRestAPI/Exceptions/ProductNotFoundException.java diff --git a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java index e0a83df..90d2196 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java @@ -1,6 +1,5 @@ package com.SpringRestAPI.Controllers; - import com.SpringRestAPI.Models.Customer; import com.SpringRestAPI.Services.CustomerService; import org.springframework.web.bind.annotation.*; @@ -20,7 +19,13 @@ public CustomerController(CustomerService customerService) { // create new customer @PostMapping("/customer") - public String addNewCustomer(@RequestBody Customer customer ) { + public String addNewCustomer( + @RequestHeader("API-Key") String apiKey, + @RequestBody Customer customer ) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } + Logger myLogger = Logger.getLogger("CustomerController new customer"); myLogger.info("Adding new customer "); @@ -34,7 +39,12 @@ public String addNewCustomer(@RequestBody Customer customer ) { // get all customer @GetMapping("/customer") - public List getCustomers() { + public List getCustomers( + @RequestHeader("API-Key") String apiKey) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } + Logger myLogger = Logger.getLogger("CustomerService get all customers"); myLogger.info("Getting all customers"); @@ -43,7 +53,13 @@ public List getCustomers() { // get customer by email @GetMapping("/customer/{customerEmail}") - public List getCustomers(@PathVariable String customerEmail) { + public List getCustomers( + @RequestHeader("API-Key") String apiKey, + @PathVariable String customerEmail) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } + Logger myLogger = Logger.getLogger("CustomerService getting customer by email"); myLogger.info("Getting customer by email"); @@ -52,7 +68,14 @@ public List getCustomers(@PathVariable String customerEmail) { // update customer name @PutMapping("/customer/{currentName}/{newName}") - public Customer updateCustomerName(@PathVariable String currentName, @PathVariable String newName) { + public Customer updateCustomerName( + @RequestHeader("API-Key") String apiKey, + @PathVariable String currentName, + @PathVariable String newName) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } + Logger myLogger = Logger.getLogger("CustomerController update customer name"); myLogger.info("Updating customer name"); @@ -61,14 +84,16 @@ public Customer updateCustomerName(@PathVariable String currentName, @PathVariab // delete customer @DeleteMapping("/customer/{customerName}") - public List deleteCustomer(@PathVariable String customerName) { + public List deleteCustomer( + @RequestHeader("API-Key") String apiKey, + @PathVariable String customerName) { + if (!"123456".equals(apiKey)) { + throw new RuntimeException("Invalid API Key"); + } + Logger myLogger = Logger.getLogger("CustomerController delete customer name"); myLogger.info("Deleting customer name"); return customerService.deleteCustomer(customerName); } - - - - -} +} \ No newline at end of file diff --git a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java index b3a3012..65f0590 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java @@ -1,8 +1,13 @@ package com.SpringRestAPI.Controllers; +import com.SpringRestAPI.Exceptions.InvalidPriceRangeException; +import com.SpringRestAPI.Exceptions.MissingApiKeyException; +import com.SpringRestAPI.Exceptions.ProductNotFoundException; import com.SpringRestAPI.Models.Product; import com.SpringRestAPI.Models.ProductCategories; import com.SpringRestAPI.Services.ProductService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -26,7 +31,7 @@ public Product addNewProduct( @RequestBody Product product ) { if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + throw new MissingApiKeyException("API-Key header is missing or invalid"); } Logger myLogger = Logger.getLogger("ProductController"); myLogger.info("Create a new Product"); @@ -43,7 +48,7 @@ public Product addNewProduct( @GetMapping("/products") // http://localhost:8080/api/products/ public List getAllProducts(@RequestHeader("API-Key") String apiKey) { if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + throw new MissingApiKeyException("API-Key header is missing or invalid"); } Logger myLogger = Logger.getLogger("ProductList"); myLogger.info("Get all the Product list"); @@ -52,17 +57,25 @@ public List getAllProducts(@RequestHeader("API-Key") String apiKey) { } // get all products by name - @GetMapping("/products/{productName}") // http://localhost:8080/api/products/{name} - public List getProductByName( - @RequestHeader("API-Key") String apiKey, + @GetMapping("/products/{productName}") + public ResponseEntity getProductByName( + @RequestHeader(value="API-Key", required=false) String apiKey, @PathVariable String productName) { - if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + try { + if (!"123456".equals(apiKey)) { + throw new MissingApiKeyException("API-Key header is missing or invalid"); + } + List products = productService.getProductByName(productName); + if (products.isEmpty()) { + throw new ProductNotFoundException("No product found with that name"); + } + return ResponseEntity.status(HttpStatus.OK).body(products); + + } catch (MissingApiKeyException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API-Key header is missing or invalid"); + } catch (ProductNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No product found with that name"); } - Logger myLogger = Logger.getLogger("ProductList by Name"); - myLogger.info("Get Product list by Name"); - - return productService.getProductByName(productName); } // change product name @@ -72,7 +85,7 @@ public Product updateProductName( @PathVariable String newName, @RequestHeader("API-Key") String apiKey) { if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + throw new MissingApiKeyException("API-Key header is missing or invalid"); } Logger myLogger = Logger.getLogger(" by Name"); myLogger.info("change Product Name"); @@ -86,7 +99,7 @@ public List deleteProduct( @PathVariable String productName, @RequestHeader("API-Key") String apiKey) { if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + throw new MissingApiKeyException("API-Key header is missing or invalid"); } Logger myLogger = Logger.getLogger("ProductList by Name"); myLogger.info("delete Product by Name"); @@ -110,16 +123,31 @@ public List getProductByCategory( // get products by price range @GetMapping("/products/price") - public List getProductsByPriceRange( - @RequestParam double minPrice, - @RequestParam double maxPrice, - @RequestHeader("API-Key") String apiKey) { - if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + public ResponseEntity getProductsByPriceRange( + @RequestParam double min, + @RequestParam double max, + @RequestHeader(value="API-Key", required=false) String apiKey) { + + try { + if (!"123456".equals(apiKey)) { + throw new MissingApiKeyException("API-Key header is missing or invalid"); + } + if (min > max) { + throw new InvalidPriceRangeException("Min price cannot be greater than max price"); + } + List products = productService.getProductsByPriceRange(min, max); + if (products == null || products.isEmpty()) { + throw new ProductNotFoundException("No product found in this price range"); + } + return ResponseEntity.status(HttpStatus.OK).body(products); + + } catch (MissingApiKeyException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API-Key header is missing or invalid"); + } catch (InvalidPriceRangeException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Min price cannot be greater than max price"); + } catch (ProductNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No product found in this price range"); } - Logger myLogger = Logger.getLogger("ProductList by Price range"); - myLogger.info("get Product by Price range"); - return productService.getProductsByPriceRange(minPrice, maxPrice); } } diff --git a/src/main/java/com/SpringRestAPI/Exceptions/InvalidPriceRangeException.java b/src/main/java/com/SpringRestAPI/Exceptions/InvalidPriceRangeException.java new file mode 100644 index 0000000..aff03a8 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Exceptions/InvalidPriceRangeException.java @@ -0,0 +1,7 @@ +package com.SpringRestAPI.Exceptions; + +public class InvalidPriceRangeException extends RuntimeException { + public InvalidPriceRangeException(String message) { + super(message); + } +} diff --git a/src/main/java/com/SpringRestAPI/Exceptions/MissingApiKeyException.java b/src/main/java/com/SpringRestAPI/Exceptions/MissingApiKeyException.java new file mode 100644 index 0000000..b4c69fc --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Exceptions/MissingApiKeyException.java @@ -0,0 +1,7 @@ +package com.SpringRestAPI.Exceptions; + +public class MissingApiKeyException extends RuntimeException { + public MissingApiKeyException(String message) { + super(message); + } +} diff --git a/src/main/java/com/SpringRestAPI/Exceptions/ProductNotFoundException.java b/src/main/java/com/SpringRestAPI/Exceptions/ProductNotFoundException.java new file mode 100644 index 0000000..9951708 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Exceptions/ProductNotFoundException.java @@ -0,0 +1,7 @@ +package com.SpringRestAPI.Exceptions; + +public class ProductNotFoundException extends RuntimeException { + public ProductNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/SpringRestAPI/Services/ProductService.java b/src/main/java/com/SpringRestAPI/Services/ProductService.java index 52d3d91..3404030 100644 --- a/src/main/java/com/SpringRestAPI/Services/ProductService.java +++ b/src/main/java/com/SpringRestAPI/Services/ProductService.java @@ -82,10 +82,10 @@ public List getProductByCategory (ProductCategories productCategory){ } // get products by price range - public List getProductsByPriceRange (double minPrice, double maxPrice){ + public List getProductsByPriceRange (double min, double max){ List products = new ArrayList<>(); for (Product product : productList) { - if (product.getProductPrice()>=minPrice&&product.getProductPrice()<=maxPrice) { + if (product.getProductPrice()>=min&&product.getProductPrice()<=max) { products.add(product); } } From 06b1a999c040fd657ef71bd0584154e397d2b179 Mon Sep 17 00:00:00 2001 From: Eren Date: Mon, 20 Apr 2026 13:24:29 +0200 Subject: [PATCH 5/6] Final --- .../Controllers/CustomerController.java | 21 ++-- .../Controllers/ProductController.java | 117 ++++++++++-------- .../Exceptions/GlobalExceptionHandler.java | 62 ++++++++++ .../com/SpringRestAPI/Models/Customer.java | 69 ++++++----- .../com/SpringRestAPI/Models/Product.java | 69 +++++------ .../Services/CustomerService.java | 34 +++-- .../Services/ProductService.java | 28 +++-- 7 files changed, 251 insertions(+), 149 deletions(-) create mode 100644 src/main/java/com/SpringRestAPI/Exceptions/GlobalExceptionHandler.java diff --git a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java index 90d2196..447c6c1 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/CustomerController.java @@ -1,9 +1,13 @@ package com.SpringRestAPI.Controllers; +import com.SpringRestAPI.Exceptions.MissingApiKeyException; import com.SpringRestAPI.Models.Customer; import com.SpringRestAPI.Services.CustomerService; +import jakarta.validation.Valid; +// @Valid Annotations provide a consistent approach to validation, which improves readability and maintainability. +// It gives you automatic error feedback to the client, indicating exactly which fields are incorrect and why. +// @Valid is used for incoming data validation. Like 'Post' and 'Put' requests. It's not needed for others. import org.springframework.web.bind.annotation.*; - import java.util.List; import java.util.logging.Logger; @@ -19,13 +23,12 @@ public CustomerController(CustomerService customerService) { // create new customer @PostMapping("/customer") - public String addNewCustomer( + public Customer addNewCustomer( @RequestHeader("API-Key") String apiKey, - @RequestBody Customer customer ) { + @Valid @RequestBody Customer customer ) { if (!"123456".equals(apiKey)) { - throw new RuntimeException("Invalid API Key"); + throw new MissingApiKeyException("API-Key header is missing or invalid"); } - Logger myLogger = Logger.getLogger("CustomerController new customer"); myLogger.info("Adding new customer "); @@ -70,7 +73,7 @@ public List getCustomers( @PutMapping("/customer/{currentName}/{newName}") public Customer updateCustomerName( @RequestHeader("API-Key") String apiKey, - @PathVariable String currentName, + @Valid @PathVariable String currentName, @PathVariable String newName) { if (!"123456".equals(apiKey)) { throw new RuntimeException("Invalid API Key"); @@ -84,7 +87,7 @@ public Customer updateCustomerName( // delete customer @DeleteMapping("/customer/{customerName}") - public List deleteCustomer( + public Customer deleteCustomer( @RequestHeader("API-Key") String apiKey, @PathVariable String customerName) { if (!"123456".equals(apiKey)) { @@ -94,6 +97,8 @@ public List deleteCustomer( Logger myLogger = Logger.getLogger("CustomerController delete customer name"); myLogger.info("Deleting customer name"); - return customerService.deleteCustomer(customerName); + return customerService.deleteCustomer(customerName) + .orElseThrow(() -> new RuntimeException("Customer not found")); } + } \ No newline at end of file diff --git a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java index 65f0590..9e43ed8 100644 --- a/src/main/java/com/SpringRestAPI/Controllers/ProductController.java +++ b/src/main/java/com/SpringRestAPI/Controllers/ProductController.java @@ -6,7 +6,10 @@ import com.SpringRestAPI.Models.Product; import com.SpringRestAPI.Models.ProductCategories; import com.SpringRestAPI.Services.ProductService; -import org.springframework.http.HttpStatus; +import jakarta.validation.Valid; +// @Valid Annotations provide a consistent approach to validation, which improves readability and maintainability. +// It gives you automatic error feedback to the client, indicating exactly which fields are incorrect and why. +// @Valid is used for incoming data validation. Like 'Post' and 'Put' requests. It's not needed for others. import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -28,8 +31,7 @@ public ProductController(ProductService productService) { @PostMapping("/products") // http://localhost:8080/api/products/ public Product addNewProduct( @RequestHeader("API-Key") String apiKey, - @RequestBody Product product - ) { + @Valid @RequestBody Product product ) { if (!"123456".equals(apiKey)) { throw new MissingApiKeyException("API-Key header is missing or invalid"); } @@ -56,32 +58,22 @@ public List getAllProducts(@RequestHeader("API-Key") String apiKey) { return productService.getProductList(); } - // get all products by name + // Get product by name @GetMapping("/products/{productName}") - public ResponseEntity getProductByName( - @RequestHeader(value="API-Key", required=false) String apiKey, + public Product getProductByName( + @RequestHeader(value="API-Key") String apiKey, @PathVariable String productName) { - try { - if (!"123456".equals(apiKey)) { - throw new MissingApiKeyException("API-Key header is missing or invalid"); - } - List products = productService.getProductByName(productName); - if (products.isEmpty()) { - throw new ProductNotFoundException("No product found with that name"); - } - return ResponseEntity.status(HttpStatus.OK).body(products); - - } catch (MissingApiKeyException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API-Key header is missing or invalid"); - } catch (ProductNotFoundException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No product found with that name"); + if (!"123456".equals(apiKey)) { + throw new MissingApiKeyException("API-Key header is missing or invalid"); } + return productService.getProductByName(productName) + .orElseThrow(() -> new ProductNotFoundException("Product not found")); } // change product name @PutMapping("/products/{productName}/{newName}") // http://localhost:8080/api/products/{name}/{newName} public Product updateProductName( - @PathVariable String productName, + @Valid @PathVariable String productName, @PathVariable String newName, @RequestHeader("API-Key") String apiKey) { if (!"123456".equals(apiKey)) { @@ -95,16 +87,17 @@ public Product updateProductName( // delete product by name @DeleteMapping("/products/{productName}") // http://localhost:8080/api/products/{productName} - public List deleteProduct( + public Product deleteProduct( @PathVariable String productName, @RequestHeader("API-Key") String apiKey) { if (!"123456".equals(apiKey)) { throw new MissingApiKeyException("API-Key header is missing or invalid"); } Logger myLogger = Logger.getLogger("ProductList by Name"); - myLogger.info("delete Product by Name"); + myLogger.info("delete Product by Name" + productName); - return productService.deleteProduct(productName); + return productService.deleteProduct(productName) + .orElseThrow(() -> new ProductNotFoundException("Product not found")); } // get item by category @@ -122,32 +115,58 @@ public List getProductByCategory( } // get products by price range - @GetMapping("/products/price") - public ResponseEntity getProductsByPriceRange( - @RequestParam double min, - @RequestParam double max, - @RequestHeader(value="API-Key", required=false) String apiKey) { - - try { - if (!"123456".equals(apiKey)) { - throw new MissingApiKeyException("API-Key header is missing or invalid"); - } - if (min > max) { - throw new InvalidPriceRangeException("Min price cannot be greater than max price"); - } - List products = productService.getProductsByPriceRange(min, max); - if (products == null || products.isEmpty()) { - throw new ProductNotFoundException("No product found in this price range"); - } - return ResponseEntity.status(HttpStatus.OK).body(products); - - } catch (MissingApiKeyException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("API-Key header is missing or invalid"); - } catch (InvalidPriceRangeException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Min price cannot be greater than max price"); - } catch (ProductNotFoundException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No product found in this price range"); + @GetMapping("/products/price") // http://localhost:8080/api/products/price?min=10&max=30 + public ResponseEntity> getProductsByPriceRange( + @RequestParam double min, // @RequestParam is /price > ?min=VALUE + @RequestParam double max, // &max=VALUE + @RequestHeader(value="API-Key") String apiKey) { + // Check API Key presence and validity + if (!"123456".equals(apiKey)) { + throw new MissingApiKeyException("API-Key header is missing or invalid"); } + // Check for valid price range + if (min > max) { + throw new InvalidPriceRangeException("Min price cannot be greater than max price"); + } + // Business logic to find products by price range + List products = productService.getProductsByPriceRange(min, max); + if (products == null || products.isEmpty()) { + throw new ProductNotFoundException("No product found in this price range"); + } + return ResponseEntity.ok(products); } + +/// IF YOU ARE READING THIS +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW +/// MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW + + /* + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⡷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠋⠈⠻⣮⣳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⡿⠋⠀⠀⠀⠀⠙⣿⣿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⡿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠈⠛⠛⠿⠿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣾⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠻⠿⣿⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⣀⣠⣤⣤⣀⡀⠀⠀⣀⣴⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⣿⣷⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣄⠀⠀ + ⢀⣤⣾⡿⠟⠛⠛⢿⣿⣶⣾⣿⠟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⣿⣷⣦⣀⣀⣤⣶⣿⡿⠿⢿⣿⡀⠀ + ⣿⣿⠏⠀⢰⡆⠀⠀⠉⢿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢿⡿⠟⠋⠁⠀⠀⢸⣿⠇⠀ + ⣿⡟⠀⣀⠈⣀⡀⠒⠃⠀⠙⣿⡆⠀⠀⠀⠀⠀⠀⠀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠇⠀ + ⣿⡇⠀⠛⢠⡋⢙⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀ + ⣿⣧⠀⠀⠀⠓⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠋⠀⠀⢸⣧⣤⣤⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⡿⠀⠀ + ⣿⣿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠻⣷⣶⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⠁⠀⠀ + ⠈⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡏⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⡄⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠻⠿⢿⣿⣷⣶⣦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠛⠿⠿⣿⣷⣶⣶⣤⣤⣀⡀⠀⠀⠀⢀⣴⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⡿⣄ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠛⠿⠿⣿⣷⣶⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣹ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⠀⠀⠀⠀⠀⢸⣧ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣆⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣶⣾⣿⣿⣿⣿⣤⣄⣀⡀⠀⠀⠀⣿ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣻⣷⣶⣾⣿⣿⡿⢯⣛⣛⡋⠁⠀⠀⠉⠙⠛⠛⠿⣿⣿⡷⣶⣿ + */ + } diff --git a/src/main/java/com/SpringRestAPI/Exceptions/GlobalExceptionHandler.java b/src/main/java/com/SpringRestAPI/Exceptions/GlobalExceptionHandler.java new file mode 100644 index 0000000..182a100 --- /dev/null +++ b/src/main/java/com/SpringRestAPI/Exceptions/GlobalExceptionHandler.java @@ -0,0 +1,62 @@ +package com.SpringRestAPI.Exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; + +import java.util.HashMap; +import java.util.Map; + +/// @ControllerAdvice provides a centralized mechanism to handle exceptions across all your REST controllers. +/// It allows you to define ways to handle specific exception types and craft consistent, meaningful responses. + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ProductNotFoundException.class) + public ResponseEntity handleProductNotFound(ProductNotFoundException ex, WebRequest request) { + return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(MissingApiKeyException.class) + public ResponseEntity handleMissingApiKey(MissingApiKeyException ex) { + return new ResponseEntity<>(ex.getMessage(), HttpStatus.FORBIDDEN); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) // For product and customer model validations + public ResponseEntity> handleValidationExceptions(MethodArgumentNotValidException ex) { + /// Happens when Spring validates your request body or parameters + /// and finds problems (like a @NotNull or @Min annotation failing) + + Map errors = new HashMap<>(); /// Instead of returning just one error, + /// you might have multiple fields failing, so we use a HashMap to return each field and its error message. + + ex.getBindingResult().getAllErrors().forEach(error -> { /// gives all validation errors from the request. + String fieldName = ((FieldError) error).getField(); /// Cast each error to FieldError so we can get the field name. + String errorMessage = error.getDefaultMessage(); /// Get the default message + errors.put(fieldName, errorMessage); /// Put it in the Map with fieldName as key and errorMessage as value. + }); + return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); + /// Return all errors as a JSON object with 400 Bad Request + } + + /// If a field fails validation, Spring creates a FieldError object. + /// FieldError contains info about: + + /// field: the name of the field that failed (name or price) + /// rejectedValue: the value the user sent + /// defaultMessage: the message you wrote in the annotation + + /// getDefaultMessage() returns the validation message you wrote in the annotation + + @ExceptionHandler(InvalidPriceRangeException.class) + public ResponseEntity handleInvalidPriceRange(InvalidPriceRangeException ex) { + return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/SpringRestAPI/Models/Customer.java b/src/main/java/com/SpringRestAPI/Models/Customer.java index 9c2fde7..d30b855 100644 --- a/src/main/java/com/SpringRestAPI/Models/Customer.java +++ b/src/main/java/com/SpringRestAPI/Models/Customer.java @@ -1,12 +1,39 @@ package com.SpringRestAPI.Models; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + public class Customer { + @NotBlank(message = "The Name cannot be blank") + @Size(min = 2, max = 16, message = "Name must be between 2 and 16 characters") private String customerName; + + @Email(message = "Please enter a valid e-mail address") private String customerEmail; + + @Min(value = 18, message = "Age must be at least 18") private int customerAge; + + @NotBlank(message = "The Address cannot be blank") private String customerAddress; + + /// @NotBlank: Ensures that the annotated string is not null or consists of only whitespace characters. + /// This is useful for fields like name and address to ensure that they are filled with meaningful data. + + /// @Size: Validates that the annotated string's length is within the specified range (min and max). + /// This helps enforce constraints on text fields, such as ensuring a name is neither too short nor too long. + + /// @Email: Validates that the annotated string is a well-formed email address. + /// This is crucial for preventing invalid email formats in your system. + + /// @Min: Checks that the annotated integer is at least a specified value. + /// In this case it is 18. Which is often used for age restrictions. + + public Customer(String customerName, String customerEmail, int customerAge, String customerAddress) { this.customerName = customerName; this.customerEmail = customerEmail; @@ -19,12 +46,7 @@ public String getCustomerName() { } public void setCustomerName(String customerName) { - if (customerName == null || customerName.trim().isEmpty()) { - throw new IllegalArgumentException("Customer name is cannot be empty"); - } - else { - this.customerName = customerName; - } + this.customerName = customerName; } public String getCustomerEmail() { @@ -32,14 +54,7 @@ public String getCustomerEmail() { } public void setCustomerEmail(String customerEmail) { - if (customerEmail == null || - !customerEmail.contains("@") || - !customerEmail.contains(".") || - customerEmail.contains(" ")) { - throw new IllegalArgumentException("Customer email is invalid"); - } else { - this.customerEmail = customerEmail; - } + this.customerEmail = customerEmail; } public int getCustomerAge() { @@ -47,11 +62,7 @@ public int getCustomerAge() { } public void setCustomerAge(int customerAge) { - if (customerAge < 18) { - throw new IllegalArgumentException("Sorry, you must be at least 18!"); - } else { - this.customerAge = customerAge; - } + this.customerAge = customerAge; } public String getCustomerAddress() { @@ -59,20 +70,10 @@ public String getCustomerAddress() { } public void setCustomerAddress(String customerAddress) { - if (customerAddress == null || customerAddress.trim().isEmpty()) { - throw new IllegalArgumentException("Customer address is cannot be empty"); - } else { - this.customerAddress = customerAddress; - } - } - - @Override - public String toString() { - return "Customer{" + - "customerName='" + customerName + '\'' + - ", customerEmail='" + customerEmail + '\'' + - ", customerAge=" + customerAge + - ", customerAddress='" + customerAddress + '\'' + - '}'; + this.customerAddress = customerAddress; } } + + + + diff --git a/src/main/java/com/SpringRestAPI/Models/Product.java b/src/main/java/com/SpringRestAPI/Models/Product.java index 186cea3..1a86e63 100644 --- a/src/main/java/com/SpringRestAPI/Models/Product.java +++ b/src/main/java/com/SpringRestAPI/Models/Product.java @@ -1,11 +1,35 @@ package com.SpringRestAPI.Models; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; + public class Product { - String productName; - double productPrice; - ProductCategories productCategory; - int productQuantity; + + @NotBlank(message = "The name cannot be blank") + @Size(min = 3, max = 12, message = "Name must be between 3 and 12 characters") + private String productName; + + @Positive(message = "Price cannot be negative") + private double productPrice; + + @NotNull(message = "The Category cannot be blank") + private ProductCategories productCategory; + + @Positive(message = "Quantity cannot be negative") + private int productQuantity; + + /// @NotBlank: Ensures that the annotated string is not null or consists of only whitespace characters. + /// This is useful for fields like name and address to ensure that they are filled with meaningful data. + + + /// @Size: Validates that the annotated string's length is within the specified range (min and max). + /// This helps enforce constraints on text fields, such as ensuring a name is neither too short nor too long. + + /// @Positive: Ensures that the annotated number is strictly greater than 0. + /// This is useful for values that must always be positive, such as quantities, prices, or IDs. public Product(String productName, double productPrice, ProductCategories productCategory, int productQuantity) { this.productName = productName; @@ -19,12 +43,7 @@ public String getProductName() { } public void setProductName(String productName) { - if (productName !=null && productName.trim().length() >= 3) { - this.productName = productName; - } - else { - throw new IllegalArgumentException("Product name must contain at least 3 characters."); - } + this.productName = productName; } public double getProductPrice() { @@ -32,12 +51,7 @@ public double getProductPrice() { } public void setProductPrice(double productPrice) { - if (productPrice > 0) { - this.productPrice = productPrice; - } - else { - throw new IllegalArgumentException("Product price cannot be negative."); - } + this.productPrice = productPrice; } public ProductCategories getProductCategory() { @@ -45,12 +59,7 @@ public ProductCategories getProductCategory() { } public void setProductCategory(ProductCategories productCategory) { - if (productCategory != null) { - this.productCategory = productCategory; - } - else { - throw new IllegalArgumentException("Product category cannot be empty."); - } + this.productCategory = productCategory; } public int getProductQuantity() { @@ -58,21 +67,7 @@ public int getProductQuantity() { } public void setProductQuantity(int productQuantity) { - if (productQuantity > 0) { - this.productQuantity = productQuantity; - } - else { - throw new IllegalArgumentException("Product quantity cannot be negative."); - } + this.productQuantity = productQuantity; } - @Override - public String toString() { - return "Product{" + - "productName='" + productName + '\'' + - ", productPrice=" + productPrice + - ", productCategory=" + productCategory + - ", productQuantity=" + productQuantity + - '}'; - } } diff --git a/src/main/java/com/SpringRestAPI/Services/CustomerService.java b/src/main/java/com/SpringRestAPI/Services/CustomerService.java index d8aad9e..94e66f1 100644 --- a/src/main/java/com/SpringRestAPI/Services/CustomerService.java +++ b/src/main/java/com/SpringRestAPI/Services/CustomerService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Service public class CustomerService { @@ -29,9 +30,10 @@ public List getCustomers() { } // add new customer - public String addNewCustomer(String customerName, String customerEmail, int customerAge, String customerAddress) { - customers.add(new Customer(customerName, customerEmail, customerAge, customerAddress)); - return "new customer added"; + public Customer addNewCustomer(String customerName, String customerEmail, int customerAge, String customerAddress) { + Customer newCustomer = new Customer(customerName, customerEmail, customerAge, customerAddress); + customers.add(newCustomer); + return newCustomer; } // get customer by email @@ -57,13 +59,27 @@ public Customer updateCustomerName(String currentName, String newName) { } // delete customer - public List deleteCustomer (String customerName){ - for (Customer customer : customers) { - if (customer.getCustomerName().equals(customerName)) { - customers.remove(customer); + public Optional deleteCustomer(String customerName) { /// Optional because we're deleting one + Optional found = customers.stream() /// This takes your list and turns into Stream. + /// Stream lets you process elements one by one instead of writing loops manually + + .filter(p -> p.getCustomerName().equals(customerName)) + /// This keeps only the customers that match the name + /// p -> ... lambda function (short version of a method) + + .findFirst(); + /// Gives the first element from the filtered results. + + found.ifPresent(customers::remove); + /// if a product was found, then execute this code + /// Long version: + /* + if (found.isPresent()) { + productList.remove(found.get()); } - } - return customers; + */ + return found; + /// Returns results or Exception if not found } diff --git a/src/main/java/com/SpringRestAPI/Services/ProductService.java b/src/main/java/com/SpringRestAPI/Services/ProductService.java index 3404030..3280026 100644 --- a/src/main/java/com/SpringRestAPI/Services/ProductService.java +++ b/src/main/java/com/SpringRestAPI/Services/ProductService.java @@ -3,13 +3,14 @@ import com.SpringRestAPI.Models.Product; import com.SpringRestAPI.Models.ProductCategories; import org.springframework.stereotype.Service; - import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Service public class ProductService { + private List productList; public ProductService() { @@ -39,14 +40,13 @@ public List getProductList() { } // get products by name - public List getProductByName(String productName) { - List products = new ArrayList<>(); + public Optional getProductByName(String productName) { for (Product product : productList) { if (product.getProductName().equalsIgnoreCase(productName)) { - products.add(product); + return Optional.of(product); // return if product found with the name in that list } } - return products; + return Optional.empty(); // if no product found by the name, it will return empty } // update product @@ -61,13 +61,13 @@ public Product updateProductName(String currentName, String newName) { } // delete product - public List deleteProduct (String productName){ - for (Product product : productList) { - if (product.getProductName().equals(productName)) { - productList.remove(product); - } - } - return productList; + public Optional deleteProduct(String productName) { + Optional found = productList.stream() + .filter(p -> p.getProductName().equals(productName)) + .findFirst(); + + found.ifPresent(productList::remove); + return found; } // get products by category @@ -92,4 +92,8 @@ public List getProductsByPriceRange (double min, double max){ return products; } + /// Product → “There is definitely a product” + /// Optional → “There might be a product” + /// List → “There could be many products” + } From a4257d66627ed2c987d35d25ef11a77066ba5785 Mon Sep 17 00:00:00 2001 From: Eren <78030053+ilearnprogramms@users.noreply.github.com> Date: Wed, 22 Apr 2026 19:35:33 +0200 Subject: [PATCH 6/6] README.md --- README.md | 96 ++++++++++++++++--------------------------------------- 1 file changed, 27 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 3e441c9..b9019cb 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,36 @@ -![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) +I am currently learning Backend course through IronHack and this was one of my projects: -# LAB | SpringBoot REST API +Built a fully functional Spring Boot REST API from scratch! -### Instructions +I focused on applying real-world backend development practices rather than just making it “work”. Aiming for clean architecture, validation, and proper API design. -1. Fork this repo. -2. Clone your fork to your local machine. -3. Solve the challenges. +🔧 Tech Stack: - -## Deliverables +Java + Spring Boot, +Spring Web, +Spring Validation, +and Dev-Tools. -- Upon completion, add your solution to git. -- Then commit to git and push to your repo on GitHub. -- Make a pull request and paste the pull request link in the submission field in the Student Portal. +💡 Key Features Implemented: -## Tasks +Designed a Product & Customer management system +Applied input validation using annotations (e.g., constraints on name, price, email, age) +Built a service layer architecture with clean separation of concerns +Used constructor injection (no field injection) for better design +Implemented custom filtering logic (by category & price range) +Secured endpoints with a required API-Key header +Created a global exception handler to manage: +Validation errors +Missing API key +Resource not found +Invalid input scenarios +Returned proper HTTP status codes for all operations +Tested all endpoints using Postman -1. Create a Spring Boot application using Spring Initializr with the following dependencies: - - Spring Web - - Spring Boot DevTools - - Spring Boot Starter Validation +📌 Endpoints include: -2. Create a `Product` class with the following validated properties: - - name (not blank, min length 3) - - price (positive number) - - category (not blank) - - quantity (positive number) +Full CRUD operations for Products & Customers +Search by name/email +Filter by category and price range -3. Create a `ProductService` class that manages a List of Products and has methods to: - - Add a new product - - Get all products - - Get product by name - - Update product - - Delete product - - Get products by category - - Get products by price range - -4. Create a `ProductController` class that: - - Uses constructor injection for the ProductService - - Requires an "API-Key" header for all requests (value: "123456") - - Has the following endpoints: - * POST `/products` - Create new product - * GET `/products` - Get all products - * GET `/products/{name}` - Get product by name - * PUT `/products/{name}` - Update product - * DELETE `/products/{name}` - Delete product - * GET `/products/category/{category}` - Get products by category - * GET `/products/price?min={min}&max={max}` - Get products by price range - -5. Create a global exception handler that handles: - - Validation errors (return proper error messages) - - Missing API-Key header - - Product not found - - Invalid price range - -6. Create a `Customer` class with the following validated properties: - - name (not blank) - - email (valid email format) - - age (minimum 18) - - address (not blank) - -7. Create a `CustomerController` with endpoints to: - - Create new customer (with validation) - - Get all customers - - Get customer by email - - Update customer - - Delete customer - -**Remember**: -- Use proper package structure -- Use constructor injection instead of @Autowired -- Test all endpoints using Postman -- Include appropriate error handling -- Use meaningful variable and method names -- Return appropriate HTTP status codes -- Include validation messages in responses +This project helped reinforce how important structured code, validation, and error handling are in building production-ready APIs.