From f222c06a83867be0e6059ce9e06156e0b3cbfaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Selim=20Helvac=C4=B1?= Date: Fri, 24 Apr 2026 14:53:15 +0200 Subject: [PATCH] Lab finished --- .../example/labweek5/LabWeek5Application.java | 13 ++++ .../controller/CustomerController.java | 45 +++++++++++ .../controller/ProductController.java | 77 +++++++++++++++++++ .../ValidationExceptionHandler.java | 34 ++++++++ .../exception/GlobalExceptionHandlerEx.java | 50 ++++++++++++ .../labweek5/exception/InvalidApiKeyEx.java | 7 ++ .../exception/InvalidPriceRangeEx.java | 7 ++ .../labweek5/exception/ProductNotFoundEx.java | 7 ++ .../com/example/labweek5/models/Customer.java | 47 +++++++++++ .../com/example/labweek5/models/Product.java | 61 +++++++++++++++ .../labweek5/service/CustomerService.java | 47 +++++++++++ .../labweek5/service/ProductService.java | 69 +++++++++++++++++ src/main/resources/application.properties | 1 + .../labweek5/LabWeek5ApplicationTests.java | 13 ++++ 14 files changed, 478 insertions(+) create mode 100644 src/main/java/com/example/labweek5/LabWeek5Application.java create mode 100644 src/main/java/com/example/labweek5/controller/CustomerController.java create mode 100644 src/main/java/com/example/labweek5/controller/ProductController.java create mode 100644 src/main/java/com/example/labweek5/controller/ValidationExceptionHandler.java create mode 100644 src/main/java/com/example/labweek5/exception/GlobalExceptionHandlerEx.java create mode 100644 src/main/java/com/example/labweek5/exception/InvalidApiKeyEx.java create mode 100644 src/main/java/com/example/labweek5/exception/InvalidPriceRangeEx.java create mode 100644 src/main/java/com/example/labweek5/exception/ProductNotFoundEx.java create mode 100644 src/main/java/com/example/labweek5/models/Customer.java create mode 100644 src/main/java/com/example/labweek5/models/Product.java create mode 100644 src/main/java/com/example/labweek5/service/CustomerService.java create mode 100644 src/main/java/com/example/labweek5/service/ProductService.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/com/example/labweek5/LabWeek5ApplicationTests.java diff --git a/src/main/java/com/example/labweek5/LabWeek5Application.java b/src/main/java/com/example/labweek5/LabWeek5Application.java new file mode 100644 index 0000000..21bcb80 --- /dev/null +++ b/src/main/java/com/example/labweek5/LabWeek5Application.java @@ -0,0 +1,13 @@ +package com.example.labweek5; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LabWeek5Application { + + public static void main(String[] args) { + SpringApplication.run(LabWeek5Application.class, args); + } + +} diff --git a/src/main/java/com/example/labweek5/controller/CustomerController.java b/src/main/java/com/example/labweek5/controller/CustomerController.java new file mode 100644 index 0000000..8cf3a9e --- /dev/null +++ b/src/main/java/com/example/labweek5/controller/CustomerController.java @@ -0,0 +1,45 @@ +package com.example.labweek5.controller; + + +import com.example.labweek5.models.Customer; +import com.example.labweek5.service.CustomerService; +import jakarta.validation.Valid; +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; + } + + @PostMapping + public Customer createNewCustomer(@Valid @RequestBody Customer customer){ + return customerService.addNewCustomer(customer); + } + + @GetMapping + public List getAllCustomers(){ + return customerService.getAllCustomers(); + } + + @GetMapping("/{email}") + public Customer getCustomerByEmail (@Valid @PathVariable String email){ + return customerService.getCustomerByEmail(email); + } + + @PutMapping("/{email}") + public Customer updateCustomer (@Valid @PathVariable String email, @Valid @RequestBody Customer updatedCustomer){ + return customerService.updateCustomer(email, updatedCustomer); + } + + @DeleteMapping("/{email}") + public void deleteCustomer (@Valid @PathVariable String email){ + customerService.deleteCustomer(email); + } + +} diff --git a/src/main/java/com/example/labweek5/controller/ProductController.java b/src/main/java/com/example/labweek5/controller/ProductController.java new file mode 100644 index 0000000..2cfc134 --- /dev/null +++ b/src/main/java/com/example/labweek5/controller/ProductController.java @@ -0,0 +1,77 @@ +package com.example.labweek5.controller; + +//import com.example.labweek5.exception.InvalidApiKeyEx; +import com.example.labweek5.models.Product; +import com.example.labweek5.service.ProductService; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static org.apache.logging.log4j.util.StringBuilders.equalsIgnoreCase; + +@RestController +@RequestMapping("/products") +public class ProductController { + private final ProductService productService; + private final String API_KEY = "123456"; + + public ProductController(ProductService productService) { + this.productService = productService; + } + + + private void apiKeyCheck(String apiKey) { + if (!apiKey.equals(API_KEY)) { + throw new RuntimeException("Invalid or missing API-Key!!"); + } + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Product createNewProduct(@RequestHeader("API-KEY") String apiKey, @Valid @RequestBody Product product) { + apiKeyCheck(apiKey); + return productService.addNewProduct(product); + } + + @GetMapping + public List getAllProducts(@RequestHeader("API-KEY") String apiKey) { + apiKeyCheck(apiKey); + return productService.getAllProducts(); + } + + @GetMapping("/{name}") + public Product getProductByName(@RequestHeader("API-KEY") String apiKey, @Valid @PathVariable String name) { + apiKeyCheck(apiKey); + return productService.getProductByName(name); + } + + @PutMapping("/{name}") + public Product updateProduct(@RequestHeader("API-KEY") String apiKey, @Valid @PathVariable String name, @RequestBody Product updatedProduct) { + apiKeyCheck(apiKey); + return productService.updateProduct(name, updatedProduct); + } + + @DeleteMapping("/{name}") + public ResponseEntity deleteProduct(@RequestHeader("API-KEY") String apiKey, @PathVariable String name) { + apiKeyCheck(apiKey); + productService.deleteProduct(name); + return ResponseEntity.noContent().build(); + } + + @GetMapping("/category/{category}") + public List getByCategory(@RequestHeader("API-KEY") String apiKey, @Valid @PathVariable String category) { + apiKeyCheck(apiKey); + return productService.getProductByCategory(category); + } + + @GetMapping("/price") + public List getByPriceRange(@RequestHeader("API-KEY") String apiKey, @Valid @RequestParam long min, @Valid @RequestParam long max) { + apiKeyCheck(apiKey); + return productService.getProductsByPriceRange(min, max); + } + +} + diff --git a/src/main/java/com/example/labweek5/controller/ValidationExceptionHandler.java b/src/main/java/com/example/labweek5/controller/ValidationExceptionHandler.java new file mode 100644 index 0000000..dedf510 --- /dev/null +++ b/src/main/java/com/example/labweek5/controller/ValidationExceptionHandler.java @@ -0,0 +1,34 @@ +package com.example.labweek5.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestControllerAdvice +public class ValidationExceptionHandler { + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity>> handleValidationErrors( + MethodArgumentNotValidException ex) { + + Map> errors = new HashMap<>(); + + ex.getBindingResult().getFieldErrors() + .forEach(error -> { + String field = error.getField(); + String message = error.getDefaultMessage(); + errors.computeIfAbsent(field, k -> new ArrayList<>()) + .add(message); + }); + + return ResponseEntity + .badRequest() + .body(errors); + } +} diff --git a/src/main/java/com/example/labweek5/exception/GlobalExceptionHandlerEx.java b/src/main/java/com/example/labweek5/exception/GlobalExceptionHandlerEx.java new file mode 100644 index 0000000..23dc4bd --- /dev/null +++ b/src/main/java/com/example/labweek5/exception/GlobalExceptionHandlerEx.java @@ -0,0 +1,50 @@ +package com.ironhack.labrestapi.exception; + + +import com.example.labweek5.exception.InvalidApiKeyEx; +import com.example.labweek5.exception.InvalidPriceRangeEx; +import com.example.labweek5.exception.ProductNotFoundEx; +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 GlobalExceptionHandlerEx { + + @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(InvalidApiKeyEx.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Map handleMissingApiKey(InvalidApiKeyEx ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } + + @ExceptionHandler(ProductNotFoundEx.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Map handleProductNotFound(ProductNotFoundEx ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } + + @ExceptionHandler(InvalidPriceRangeEx.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Map handleInvalidPriceRange(InvalidPriceRangeEx ex) { + Map error = new HashMap<>(); + error.put("error", ex.getMessage()); + return error; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/labweek5/exception/InvalidApiKeyEx.java b/src/main/java/com/example/labweek5/exception/InvalidApiKeyEx.java new file mode 100644 index 0000000..6d99ea2 --- /dev/null +++ b/src/main/java/com/example/labweek5/exception/InvalidApiKeyEx.java @@ -0,0 +1,7 @@ +package com.example.labweek5.exception; + +public class InvalidApiKeyEx extends RuntimeException{ + public InvalidApiKeyEx(String message){ + super(message); + } +} diff --git a/src/main/java/com/example/labweek5/exception/InvalidPriceRangeEx.java b/src/main/java/com/example/labweek5/exception/InvalidPriceRangeEx.java new file mode 100644 index 0000000..6c76fdc --- /dev/null +++ b/src/main/java/com/example/labweek5/exception/InvalidPriceRangeEx.java @@ -0,0 +1,7 @@ +package com.example.labweek5.exception; + +public class InvalidPriceRangeEx extends RuntimeException { + public InvalidPriceRangeEx(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/labweek5/exception/ProductNotFoundEx.java b/src/main/java/com/example/labweek5/exception/ProductNotFoundEx.java new file mode 100644 index 0000000..1fbcdba --- /dev/null +++ b/src/main/java/com/example/labweek5/exception/ProductNotFoundEx.java @@ -0,0 +1,7 @@ +package com.example.labweek5.exception; + +public class ProductNotFoundEx extends RuntimeException { + public ProductNotFoundEx(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/labweek5/models/Customer.java b/src/main/java/com/example/labweek5/models/Customer.java new file mode 100644 index 0000000..e19e6a6 --- /dev/null +++ b/src/main/java/com/example/labweek5/models/Customer.java @@ -0,0 +1,47 @@ +package com.example.labweek5.models; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; + +public class Customer { + + @Email + private String email; + + @Min(18) + private int age; + + @NotBlank + private String address; + + public Customer(String email, int age, String address) { + this.email = email; + this.age = age; + this.address = address; + } + + 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/src/main/java/com/example/labweek5/models/Product.java b/src/main/java/com/example/labweek5/models/Product.java new file mode 100644 index 0000000..e3cf7f0 --- /dev/null +++ b/src/main/java/com/example/labweek5/models/Product.java @@ -0,0 +1,61 @@ +package com.example.labweek5.models; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Positive; +import org.hibernate.validator.constraints.Length; + +public class Product { + + @NotBlank (message = "Name cannot be blank" ) + @Length(min = 3, message = "Min length 3") + private String name; + + @Positive (message = "Price must be positive") + private double price; + + @NotBlank (message = " Category cannot be blank") + private String category; + + @Positive (message = "Quantity must be positive") + 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) { + 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) { + this.quantity = quantity; + } +} diff --git a/src/main/java/com/example/labweek5/service/CustomerService.java b/src/main/java/com/example/labweek5/service/CustomerService.java new file mode 100644 index 0000000..7b37f47 --- /dev/null +++ b/src/main/java/com/example/labweek5/service/CustomerService.java @@ -0,0 +1,47 @@ +package com.example.labweek5.service; + +import com.example.labweek5.models.Customer; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class CustomerService { + + private List customerList = new ArrayList<>(); + + public Customer addNewCustomer (Customer customer){ + customerList.add(customer); + return customer; + } + + public List getAllCustomers(){ + return customerList; + } + + public Customer getCustomerByEmail(String email){ + for (Customer customer : customerList){ + if( customer.getEmail().equalsIgnoreCase(email)){ + return customer; + } + } + return null; + } + + public Customer updateCustomer (String email, Customer updatedCustomer){ + for (Customer customer : customerList){ + if(customer.getEmail().equalsIgnoreCase(email)){ + customer.setAddress(updatedCustomer.getAddress()); + customer.setAge(updatedCustomer.getAge()); + customer.setEmail(updatedCustomer.getEmail()); + return customer; + } + } return null; + } + + public void deleteCustomer(String email){ + customerList.remove(email); + } + +} diff --git a/src/main/java/com/example/labweek5/service/ProductService.java b/src/main/java/com/example/labweek5/service/ProductService.java new file mode 100644 index 0000000..ff5ec2c --- /dev/null +++ b/src/main/java/com/example/labweek5/service/ProductService.java @@ -0,0 +1,69 @@ +package com.example.labweek5.service; + +import com.example.labweek5.models.Product; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class ProductService { + + private List productList = new ArrayList<>(); + + public Product addNewProduct(Product product){ + productList.add(product); + return product; + } + + public List getAllProducts(){ + return productList; + } + + public Product getProductByName(String name) { + for (Product product : productList) { + if (product.getName().equalsIgnoreCase(name)) { + return product; + } + } + return null; + } + + public Product updateProduct (String name, Product updatedProduct){ + for (Product product : productList ){ + if (product.getName().equalsIgnoreCase(name)){ + product.setPrice(updatedProduct.getPrice()); + product.setCategory(updatedProduct.getCategory()); + product.setQuantity(updatedProduct.getQuantity()); + product.setName(updatedProduct.getName()); + return product; + } + } + return null; + } + + public void deleteProduct(String name){ + productList.remove(name); + } + + public List getProductByCategory(String requestedCategory){ + List foundProduct = new ArrayList<>(); + for (Product product : productList){ + if (product.getCategory().equalsIgnoreCase(requestedCategory)){ + foundProduct.add(product); + } + } + return foundProduct; + } + + public List getProductsByPriceRange(long minPrice, long maxPrice){ + List resultList=new ArrayList<>(); + for(Product product: productList){ + if(product.getPrice()>=minPrice && product.getPrice()<=maxPrice){ + resultList.add(product); + } + } + return resultList; + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..be65ce0 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=LabWeek5 diff --git a/src/test/java/com/example/labweek5/LabWeek5ApplicationTests.java b/src/test/java/com/example/labweek5/LabWeek5ApplicationTests.java new file mode 100644 index 0000000..cf61a18 --- /dev/null +++ b/src/test/java/com/example/labweek5/LabWeek5ApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.labweek5; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class LabWeek5ApplicationTests { + + @Test + void contextLoads() { + } + +}