diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..912c0d2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+target/
+.idea/
+
+*.iml
+*.log
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..bc3fadf
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,54 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.5
+
+
+
+ com.ironhack
+ lab-java-springboot-rest-api
+ 0.0.1-SNAPSHOT
+ lab-java-springboot-rest-api
+ LAB SpringBoot REST API - Ironhack
+
+
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/src/main/java/com/ironhack/lab/LabRestApiApplication.java b/src/main/java/com/ironhack/lab/LabRestApiApplication.java
new file mode 100644
index 0000000..b1555e3
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/LabRestApiApplication.java
@@ -0,0 +1,12 @@
+package com.ironhack.lab;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class LabRestApiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(LabRestApiApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/controller/CustomerController.java b/src/main/java/com/ironhack/lab/controller/CustomerController.java
new file mode 100644
index 0000000..5f5da39
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/controller/CustomerController.java
@@ -0,0 +1,55 @@
+package com.ironhack.lab.controller;
+
+import com.ironhack.lab.model.Customer;
+import com.ironhack.lab.service.CustomerService;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/customers")
+public class CustomerController {
+
+ private final CustomerService customerService;
+
+ public CustomerController(CustomerService customerService) {
+ this.customerService = customerService;
+ }
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public Customer createCustomer(@Valid @RequestBody Customer customer) {
+ return customerService.addCustomer(customer);
+ }
+
+ @GetMapping
+ public List getAllCustomers() {
+ return customerService.getAllCustomers();
+ }
+
+ @GetMapping("/{email}")
+ public Customer getCustomerByEmail(@PathVariable String email) {
+ return customerService.getCustomerByEmail(email);
+ }
+
+ @PutMapping("/{email}")
+ public Customer updateCustomer(@PathVariable String email, @Valid @RequestBody Customer customer) {
+ return customerService.updateCustomer(email, customer);
+ }
+
+ @DeleteMapping("/{email}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteCustomer(@PathVariable String email) {
+ customerService.deleteCustomer(email);
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/controller/ProductController.java b/src/main/java/com/ironhack/lab/controller/ProductController.java
new file mode 100644
index 0000000..6db2a7b
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/controller/ProductController.java
@@ -0,0 +1,88 @@
+package com.ironhack.lab.controller;
+
+import com.ironhack.lab.exception.InvalidApiKeyException;
+import com.ironhack.lab.model.Product;
+import com.ironhack.lab.service.ProductService;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/products")
+public class ProductController {
+
+ private static final String VALID_API_KEY = "123456";
+ private final ProductService productService;
+
+ public ProductController(ProductService productService) {
+ this.productService = productService;
+ }
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public Product createProduct(@RequestHeader("API-Key") String apiKey, @Valid @RequestBody Product product) {
+ validateApiKey(apiKey);
+ return productService.addProduct(product);
+ }
+
+ @GetMapping
+ public List getAllProducts(@RequestHeader("API-Key") String apiKey) {
+ validateApiKey(apiKey);
+ return productService.getAllProducts();
+ }
+
+ @GetMapping("/{name}")
+ public Product getProductByName(@RequestHeader("API-Key") String apiKey, @PathVariable String name) {
+ validateApiKey(apiKey);
+ return productService.getProductByName(name);
+ }
+
+ @PutMapping("/{name}")
+ public Product updateProduct(
+ @RequestHeader("API-Key") String apiKey,
+ @PathVariable String name,
+ @Valid @RequestBody Product product) {
+ validateApiKey(apiKey);
+ return productService.updateProduct(name, product);
+ }
+
+ @DeleteMapping("/{name}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteProduct(@RequestHeader("API-Key") String apiKey, @PathVariable String name) {
+ validateApiKey(apiKey);
+ productService.deleteProduct(name);
+ }
+
+ @GetMapping("/category/{category}")
+ public List getProductsByCategory(@RequestHeader("API-Key") String apiKey, @PathVariable String category) {
+ validateApiKey(apiKey);
+ return productService.getProductsByCategory(category);
+ }
+
+ @GetMapping("/price")
+ public List getProductsByPriceRange(
+ @RequestHeader("API-Key") String apiKey,
+ @RequestParam double min,
+ @RequestParam double max) {
+ validateApiKey(apiKey);
+ return productService.getProductsByPriceRange(min, max);
+ }
+
+ private void validateApiKey(String apiKey) {
+ if (!VALID_API_KEY.equals(apiKey)) {
+ throw new InvalidApiKeyException();
+ }
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/exception/CustomerNotFoundException.java b/src/main/java/com/ironhack/lab/exception/CustomerNotFoundException.java
new file mode 100644
index 0000000..a6625f3
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/exception/CustomerNotFoundException.java
@@ -0,0 +1,8 @@
+package com.ironhack.lab.exception;
+
+public class CustomerNotFoundException extends RuntimeException {
+
+ public CustomerNotFoundException(String email) {
+ super("Customer not found: " + email);
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/exception/InvalidApiKeyException.java b/src/main/java/com/ironhack/lab/exception/InvalidApiKeyException.java
new file mode 100644
index 0000000..d053cb7
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/exception/InvalidApiKeyException.java
@@ -0,0 +1,8 @@
+package com.ironhack.lab.exception;
+
+public class InvalidApiKeyException extends RuntimeException {
+
+ public InvalidApiKeyException() {
+ super("Invalid API-Key header");
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/exception/InvalidPriceRangeException.java b/src/main/java/com/ironhack/lab/exception/InvalidPriceRangeException.java
new file mode 100644
index 0000000..db68226
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/exception/InvalidPriceRangeException.java
@@ -0,0 +1,8 @@
+package com.ironhack.lab.exception;
+
+public class InvalidPriceRangeException extends RuntimeException {
+
+ public InvalidPriceRangeException() {
+ super("Invalid price range: min must be less than or equal to max");
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/exception/ProductNotFoundException.java b/src/main/java/com/ironhack/lab/exception/ProductNotFoundException.java
new file mode 100644
index 0000000..5fd24be
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/exception/ProductNotFoundException.java
@@ -0,0 +1,8 @@
+package com.ironhack.lab.exception;
+
+public class ProductNotFoundException extends RuntimeException {
+
+ public ProductNotFoundException(String name) {
+ super("Product not found: " + name);
+ }
+}
diff --git a/src/main/java/com/ironhack/lab/handler/GlobalExceptionHandler.java b/src/main/java/com/ironhack/lab/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..2bd71c6
--- /dev/null
+++ b/src/main/java/com/ironhack/lab/handler/GlobalExceptionHandler.java
@@ -0,0 +1,68 @@
+package com.ironhack.lab.handler;
+
+import com.ironhack.lab.exception.CustomerNotFoundException;
+import com.ironhack.lab.exception.InvalidApiKeyException;
+import com.ironhack.lab.exception.InvalidPriceRangeException;
+import com.ironhack.lab.exception.ProductNotFoundException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingRequestHeaderException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity