Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/lab-java-springboot-rest-api.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>

<groupId>com.ironhack</groupId>
<artifactId>lab-springboot-rest-api</artifactId>
<version>1.0.0</version>
<name>lab-springboot-rest-api</name>
<description>Lab Spring Boot REST API</description>

<properties>
<java.version>21</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.ironhack.lab;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LabSpringbootRestApiApplication {

public static void main(String[] args) {
SpringApplication.run(LabSpringbootRestApiApplication.class, args);
}
}

55 changes: 55 additions & 0 deletions src/main/java/com/ironhack/lab/controller/CustomerController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.ironhack.lab.controller;

import com.ironhack.lab.exception.CustomerNotFoundException;
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.*;

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<Customer> getAllCustomers() {
return customerService.getAllCustomers();
}

@GetMapping("/{email}")
public Customer getCustomerByEmail(@PathVariable String email) {
return customerService.getCustomerByEmail(email)
.orElseThrow(() -> new CustomerNotFoundException("Customer not found with email: " + email));
}

@PutMapping("/{email}")
public Customer updateCustomer(@PathVariable String email,
@Valid @RequestBody Customer customer) {
return customerService.updateCustomer(email, customer)
.orElseThrow(() -> new CustomerNotFoundException("Customer not found with email: " + email));
}

@DeleteMapping("/{email}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCustomer(@PathVariable String email) {
boolean deleted = customerService.deleteCustomer(email);
if (!deleted) {
throw new CustomerNotFoundException("Customer not found with email: " + email);
}
}
}

91 changes: 91 additions & 0 deletions src/main/java/com/ironhack/lab/controller/ProductController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.ironhack.lab.controller;

import com.ironhack.lab.exception.ApiKeyMissingException;
import com.ironhack.lab.exception.InvalidPriceRangeException;
import com.ironhack.lab.exception.ProductNotFoundException;
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.*;

import java.util.List;

@RestController
@RequestMapping("/products")
public class ProductController {

private final ProductService productService;
private static final String API_KEY = "123456";

public ProductController(ProductService productService) {
this.productService = productService;
}

private void validateApiKey(String apiKey) {
if (apiKey == null || !apiKey.equals(API_KEY)) {
throw new ApiKeyMissingException("Invalid or missing API-Key header");
}
}

@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<Product> 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)
.orElseThrow(() -> new ProductNotFoundException("Product not found with name: " + 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)
.orElseThrow(() -> new ProductNotFoundException("Product not found with name: " + name));
}

@DeleteMapping("/{name}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteProduct(@RequestHeader("API-Key") String apiKey,
@PathVariable String name) {
validateApiKey(apiKey);
boolean deleted = productService.deleteProduct(name);
if (!deleted) {
throw new ProductNotFoundException("Product not found with name: " + name);
}
}

@GetMapping("/category/{category}")
public List<Product> getProductsByCategory(@RequestHeader("API-Key") String apiKey,
@PathVariable String category) {
validateApiKey(apiKey);
return productService.getProductsByCategory(category);
}

@GetMapping("/price")
public List<Product> getProductsByPriceRange(@RequestHeader("API-Key") String apiKey,
@RequestParam Double min,
@RequestParam Double max) {
validateApiKey(apiKey);
if (min < 0 || max < 0 || min > max) {
throw new InvalidPriceRangeException("Invalid price range: min must be less than or equal to max and both must be positive");
}
return productService.getProductsByPriceRange(min, max);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ironhack.lab.exception;

public class ApiKeyMissingException extends RuntimeException {
public ApiKeyMissingException(String message) {
super(message);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ironhack.lab.exception;

public class CustomerNotFoundException extends RuntimeException {
public CustomerNotFoundException(String message) {
super(message);
}
}

65 changes: 65 additions & 0 deletions src/main/java/com/ironhack/lab/exception/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.ironhack.lab.exception;

import java.time.LocalDateTime;
import java.util.List;

public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private List<String> messages;
private String path;

public ErrorResponse() {
this.timestamp = LocalDateTime.now();
}

public ErrorResponse(int status, String error, List<String> messages, String path) {
this.timestamp = LocalDateTime.now();
this.status = status;
this.error = error;
this.messages = messages;
this.path = path;
}

public LocalDateTime getTimestamp() {
return timestamp;
}

public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}

public int getStatus() {
return status;
}

public void setStatus(int status) {
this.status = status;
}

public String getError() {
return error;
}

public void setError(String error) {
this.error = error;
}

public List<String> getMessages() {
return messages;
}

public void setMessages(List<String> messages) {
this.messages = messages;
}

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}
}

Loading