From c855b8be4ae99e12aa8cdfc451fb9f12f0a9de54 Mon Sep 17 00:00:00 2001 From: Mansura Date: Fri, 6 Mar 2026 07:32:52 +0400 Subject: [PATCH 1/3] Postmapping and getmapping are implemented correctly --- .../controller/CustomerController.java | 37 ++++++++++ .../controller/ProductController.java | 67 +++++++++++++++++++ .../rest_api/exception/CustomerNotFound.java | 7 ++ .../exception/GlobalExceptionHandler.java | 49 ++++++++++++++ .../exception/LowerBoundException.java | 7 ++ .../exception/MissingKeyHeaderException.java | 7 ++ .../exception/ProductNotFoundException.java | 7 ++ .../org/ironhack/rest_api/model/Customer.java | 58 ++++++++++++++++ .../org/ironhack/rest_api/model/Product.java | 66 ++++++++++++++++++ .../rest_api/service/CustomerService.java | 34 ++++++++++ .../rest_api/service/ProductService.java | 64 ++++++++++++++++++ 11 files changed, 403 insertions(+) create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/exception/CustomerNotFound.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/exception/GlobalExceptionHandler.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/exception/LowerBoundException.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/exception/MissingKeyHeaderException.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/exception/ProductNotFoundException.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/model/Customer.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/model/Product.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java create mode 100644 rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java diff --git a/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java b/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java new file mode 100644 index 0000000..125abcb --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java @@ -0,0 +1,37 @@ +package org.ironhack.rest_api.controller; + +import jakarta.validation.Valid; +import org.ironhack.rest_api.model.Customer; +import org.ironhack.rest_api.service.CustomerService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/customers") +public class CustomerController { + private final CustomerService customerService; + + public CustomerController(CustomerService customerService) { + this.customerService = customerService; + } + + @GetMapping + public List getCustomers() { + return customerService.getCustomers(); + } + + @GetMapping("/{email}") + public Customer getCustomer(@PathVariable String email) { + return customerService.getCustomerByEmail(email); + } + + @PostMapping + public ResponseEntity createCustomer(@Valid @RequestBody Customer customer) { + Customer created = customerService.addCustomer(customer.getName(), customer.getEmail(), customer.getAge(), customer.getAddress()); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java b/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java new file mode 100644 index 0000000..50bdc84 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java @@ -0,0 +1,67 @@ +package org.ironhack.rest_api.controller; + +import jakarta.validation.Valid; +import org.ironhack.rest_api.exception.MissingKeyHeaderException; +import org.ironhack.rest_api.model.Product; +import org.ironhack.rest_api.service.ProductService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("products") +public class ProductController { + + private final ProductService productService; + private final static String API_KEY = "123456789"; + + public ProductController(ProductService productService) { + this.productService = productService; + } + + public void checkApiKey(String apiKey) { + if (apiKey == null) { + throw new MissingKeyHeaderException("Missing API Key"); + } + if (!apiKey.matches(API_KEY)) { + throw new MissingKeyHeaderException("Invalid API Key"); + } + } + + @GetMapping + public List getProducts(@RequestHeader String apiKey) { + checkApiKey(apiKey); + return productService.findAll(); + } + + @PostMapping + public ResponseEntity addProduct(@RequestHeader String apiKey, @Valid @RequestBody Product product) { + checkApiKey(apiKey); + Product created = productService.save(product.getName(), product.getPrice(), product.getCategory(), product.getQuantity()); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + + @GetMapping("/category/{category}") + public List getProductsByCategory(@RequestHeader String apiKey, @PathVariable String category) { + checkApiKey(apiKey); + return productService.findByCategory(category); + } + + @GetMapping("/{name}") + public Product getProductsByName(@RequestHeader String apiKey, @PathVariable String name) { + checkApiKey(apiKey); + return productService.findByName(name); + } + + @GetMapping("/price") + public List getProductsByPriceRange(@RequestHeader String apiKey, + @RequestParam(required = false) double lower, + @RequestParam(required = false) double higher) { + checkApiKey(apiKey); + return productService.findByPriceRange(lower, higher); + } + + +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/exception/CustomerNotFound.java b/rest_api/src/main/java/org/ironhack/rest_api/exception/CustomerNotFound.java new file mode 100644 index 0000000..b57ea0e --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/exception/CustomerNotFound.java @@ -0,0 +1,7 @@ +package org.ironhack.rest_api.exception; + +public class CustomerNotFound extends RuntimeException { + public CustomerNotFound(String message) { + super(message); + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/exception/GlobalExceptionHandler.java b/rest_api/src/main/java/org/ironhack/rest_api/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..0877352 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/exception/GlobalExceptionHandler.java @@ -0,0 +1,49 @@ +package org.ironhack.rest_api.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Map handleValidation(MethodArgumentNotValidException ex) { + + Map errors = new HashMap<>(); + + ex.getBindingResult().getFieldErrors() + .forEach(e -> errors.put(e.getField(), e.getDefaultMessage())); + + return errors; + } + + @ExceptionHandler(MissingKeyHeaderException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Map handleMissingApiKey(MissingKeyHeaderException ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } + + @ExceptionHandler(ProductNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Map handleProductNotFound(ProductNotFoundException ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } + + @ExceptionHandler(LowerBoundException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Map handleInvalidPriceRange(LowerBoundException ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/exception/LowerBoundException.java b/rest_api/src/main/java/org/ironhack/rest_api/exception/LowerBoundException.java new file mode 100644 index 0000000..87b46b2 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/exception/LowerBoundException.java @@ -0,0 +1,7 @@ +package org.ironhack.rest_api.exception; + +public class LowerBoundException extends RuntimeException { + public LowerBoundException(String message) { + super(message); + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/exception/MissingKeyHeaderException.java b/rest_api/src/main/java/org/ironhack/rest_api/exception/MissingKeyHeaderException.java new file mode 100644 index 0000000..5ae6ac8 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/exception/MissingKeyHeaderException.java @@ -0,0 +1,7 @@ +package org.ironhack.rest_api.exception; + +public class MissingKeyHeaderException extends RuntimeException { + public MissingKeyHeaderException(String message) { + super(message); + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/exception/ProductNotFoundException.java b/rest_api/src/main/java/org/ironhack/rest_api/exception/ProductNotFoundException.java new file mode 100644 index 0000000..46e6fd9 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/exception/ProductNotFoundException.java @@ -0,0 +1,7 @@ +package org.ironhack.rest_api.exception; + +public class ProductNotFoundException extends RuntimeException { + public ProductNotFoundException(String message) { + super(message); + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/model/Customer.java b/rest_api/src/main/java/org/ironhack/rest_api/model/Customer.java new file mode 100644 index 0000000..dae4e1e --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/model/Customer.java @@ -0,0 +1,58 @@ +package org.ironhack.rest_api.model; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; + +public class Customer { + + @NotBlank(message = "Name is required") + private String name; + + @Email(message = "That must be in email format") + private String email; + @Min(value = 18, message = "Age must be 18 or greater than 18") + private int age; + + @NotBlank(message = "Address is required") + private String address; + + public Customer(String name, String email, int age, String address) { + this.name = name; + this.email = email; + this.age = age; + this.address = address; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/model/Product.java b/rest_api/src/main/java/org/ironhack/rest_api/model/Product.java new file mode 100644 index 0000000..37524f7 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/model/Product.java @@ -0,0 +1,66 @@ +package org.ironhack.rest_api.model; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; + +public class Product { + + + @NotBlank(message = "Name is required") + @Size(min = 3, message = "Name length must be consist of min 3 elements") + private String name; + + @Positive(message = "Price must be greater than 0") + private Double price; + + @NotBlank(message = "Category is required") + private String category; + + @Positive(message = "Quantity must be greater than 0") + private int quantity; + + public Product(String name, Double price, String category, int quantity) { + this.name = name; + this.price = price; + this.category = category; + this.quantity = quantity; + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + if (price < 0) + return; + this.price = price; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + if (quantity < 0) + return; + this.quantity = quantity; + } +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java b/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java new file mode 100644 index 0000000..1326998 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java @@ -0,0 +1,34 @@ +package org.ironhack.rest_api.service; + +import org.ironhack.rest_api.exception.CustomerNotFound; +import org.ironhack.rest_api.model.Customer; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +@Service +public class CustomerService { + + private final HashMap customers = new HashMap<>(); + + public List getCustomers() { + return new ArrayList<>(customers.values()); + } + + public Customer addCustomer(String name, String email, int age, String address) { + Customer customer = new Customer(name, email, age, address); + customers.put(email, customer); + return customer; + } + + public Customer getCustomerByEmail(String email) { + if (customers.containsKey(email)) { + return customers.get(email); + } + throw new CustomerNotFound("Customer with email " + email + " not found"); + } + + +} diff --git a/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java new file mode 100644 index 0000000..a1e8d04 --- /dev/null +++ b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java @@ -0,0 +1,64 @@ +package org.ironhack.rest_api.service; + +import org.ironhack.rest_api.exception.LowerBoundException; +import org.ironhack.rest_api.exception.ProductNotFoundException; +import org.ironhack.rest_api.model.Product; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class ProductService { + + private final Map products = new HashMap<>(); + + public ProductService() { + } + + public List findAll() { + return new ArrayList(products.values()); + + } + + public Product save(String name, Double price, String category, int quantity) { + Product product = new Product(name, price, category, quantity); + products.put(product.getName(), product); + return product; + + } + + public List findByCategory(String category) { + List productList = new ArrayList<>(); + for (Product p : products.values()) { + if (p.getCategory().equalsIgnoreCase(category)) { + productList.add(p); + } + } + return productList; + } + + public List findByPriceRange(double lower, double upper) { + if (lower > upper) { + throw new LowerBoundException("Lower bound is greater than upper bound"); + } + return products.values() + .stream() + .filter(product -> product.getPrice() >= lower && product.getPrice() <= upper) + .collect(Collectors.toList()); + + } + + public Product findByName(String name) { + for (Product p : products.values()) { + if (p.getName().equalsIgnoreCase(name)) { + return p; + } + } + throw new ProductNotFoundException("Product not found"); + } + +} From f69b0fb6a72658fdbeefc90b742c46f5cb518b66 Mon Sep 17 00:00:00 2001 From: Mansura Date: Tue, 10 Mar 2026 11:05:50 +0400 Subject: [PATCH 2/3] adding put and delete --- .../controller/CustomerController.java | 12 ++++++++++ .../controller/ProductController.java | 14 +++++++++++ .../rest_api/service/CustomerService.java | 14 +++++++++++ .../rest_api/service/ProductService.java | 24 ++++++++++++++----- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java b/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java index 125abcb..730099c 100644 --- a/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java +++ b/rest_api/src/main/java/org/ironhack/rest_api/controller/CustomerController.java @@ -34,4 +34,16 @@ public ResponseEntity createCustomer(@Valid @RequestBody Customer cust return ResponseEntity.status(HttpStatus.CREATED).body(created); } + @PutMapping("{email}") + public ResponseEntity updateCustomer(@PathVariable String email, @Valid @RequestBody Customer customer) { + Customer customer1=customerService.updateCustomer(customer.getName(), customer.getEmail(), customer.getAge(), customer.getAddress()); + return ResponseEntity.ok(customer1); + } + + @DeleteMapping("{email}") + public ResponseEntity deleteCustomer(@PathVariable String email) { + customerService.deleteCustomerByEmail(email); + return ResponseEntity.noContent().build(); + } + } diff --git a/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java b/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java index 50bdc84..e83a280 100644 --- a/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java +++ b/rest_api/src/main/java/org/ironhack/rest_api/controller/ProductController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import org.ironhack.rest_api.exception.MissingKeyHeaderException; +import org.ironhack.rest_api.model.Customer; import org.ironhack.rest_api.model.Product; import org.ironhack.rest_api.service.ProductService; import org.springframework.http.HttpStatus; @@ -62,6 +63,19 @@ public List getProductsByPriceRange(@RequestHeader String apiKey, checkApiKey(apiKey); return productService.findByPriceRange(lower, higher); } + @PutMapping("/{name}") + public ResponseEntity updateProduct(@RequestHeader String apiKey, @PathVariable String name, @Valid @RequestBody Product product) { + checkApiKey(apiKey); + Product product1 = productService.update(name,product.getPrice(),product.getCategory(),product.getQuantity()); + return ResponseEntity.ok(product1); + } + + @DeleteMapping("/{name}") + public void deleteProduct(@RequestHeader String apiKey, @PathVariable String name) { + checkApiKey(apiKey); + productService.delete(name); + + } } diff --git a/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java b/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java index 1326998..7f7aa2c 100644 --- a/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java +++ b/rest_api/src/main/java/org/ironhack/rest_api/service/CustomerService.java @@ -30,5 +30,19 @@ public Customer getCustomerByEmail(String email) { throw new CustomerNotFound("Customer with email " + email + " not found"); } + public Customer updateCustomer(String name, String email, int age, String address) { + Customer customer = getCustomerByEmail(email); + customer.setName(name); + customer.setAge(age); + customer.setAddress(address); + customers.put(email, customer); + return customer; + + } + public void deleteCustomerByEmail(String email) { + getCustomerByEmail(email); + customers.remove(email); + } + } diff --git a/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java index a1e8d04..6a3b4f8 100644 --- a/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java +++ b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java @@ -53,12 +53,24 @@ public List findByPriceRange(double lower, double upper) { } public Product findByName(String name) { - for (Product p : products.values()) { - if (p.getName().equalsIgnoreCase(name)) { - return p; - } - } - throw new ProductNotFoundException("Product not found"); + if (products.containsKey(name)) { + return products.get(name); + } + throw new ProductNotFoundException("Product not found"); + } + + public Product update(String name, double price, String category, int quantity) { + Product oldProduct = findByName(name); + oldProduct.setPrice(price); + oldProduct.setCategory(category); + oldProduct.setQuantity(quantity); + products.put(name, oldProduct); + return oldProduct; + } + + public void delete(String name) { + findByName(name); + products.remove(name); } } From 2b240a9d8eb0eed34d3024db9a52e84f5cd594cb Mon Sep 17 00:00:00 2001 From: Mansura Date: Tue, 10 Mar 2026 11:16:39 +0400 Subject: [PATCH 3/3] refactoring save product --- .../main/java/org/ironhack/rest_api/service/ProductService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java index 6a3b4f8..9923324 100644 --- a/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java +++ b/rest_api/src/main/java/org/ironhack/rest_api/service/ProductService.java @@ -26,7 +26,7 @@ public List findAll() { public Product save(String name, Double price, String category, int quantity) { Product product = new Product(name, price, category, quantity); - products.put(product.getName(), product); + products.put(name, product); return product; }