From 8f4d43c801e41daac1fde34984ea098e8c0a34eb Mon Sep 17 00:00:00 2001 From: David Date: Mon, 31 Aug 2026 13:38:40 +0200 Subject: [PATCH 1/3] core and extentions done --- src/main/java/com/booleanuk/api/Main.java | 11 +++ .../product/controller/ProductController.java | 58 +++++++++++++++ .../booleanuk/api/product/model/Product.java | 55 ++++++++++++++ .../api/product/model/ProductCreateDto.java | 41 +++++++++++ .../api/product/repo/ProductRepository.java | 68 ++++++++++++++++++ .../api/product/service/ProductService.java | 71 +++++++++++++++++++ 6 files changed, 304 insertions(+) create mode 100644 src/main/java/com/booleanuk/api/Main.java create mode 100644 src/main/java/com/booleanuk/api/product/controller/ProductController.java create mode 100644 src/main/java/com/booleanuk/api/product/model/Product.java create mode 100644 src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java create mode 100644 src/main/java/com/booleanuk/api/product/repo/ProductRepository.java create mode 100644 src/main/java/com/booleanuk/api/product/service/ProductService.java diff --git a/src/main/java/com/booleanuk/api/Main.java b/src/main/java/com/booleanuk/api/Main.java new file mode 100644 index 0000000..a049d53 --- /dev/null +++ b/src/main/java/com/booleanuk/api/Main.java @@ -0,0 +1,11 @@ +package com.booleanuk.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main{ + public static void main(String[] args){ + SpringApplication.run(Main.class, args); + } +} diff --git a/src/main/java/com/booleanuk/api/product/controller/ProductController.java b/src/main/java/com/booleanuk/api/product/controller/ProductController.java new file mode 100644 index 0000000..151c17c --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/controller/ProductController.java @@ -0,0 +1,58 @@ +package com.booleanuk.api.product.controller; + +import org.springframework.http.ResponseEntity; +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.RestController; + +import com.booleanuk.api.product.service.ProductService; + +import java.util.List; +import com.booleanuk.api.product.model.Product; +import com.booleanuk.api.product.model.ProductCreateDto; + +@RestController +@RequestMapping("/products") +public class ProductController{ + private ProductService productService; + + public ProductController(ProductService productService){ + this.productService = productService; + } + + @GetMapping + public ResponseEntity> getAllProduct(){ + List prods = this.productService.getAllProduct(); + return ResponseEntity.ok(prods); + } + + @GetMapping("/{id}") + public ResponseEntity getProduct(@PathVariable int id){ + ResponseEntity res = this.productService.getProduct(id); + return res; + } + + @PostMapping + public ResponseEntity createProduct(@RequestBody ProductCreateDto productDto){ + ResponseEntity res = this.productService.createProduct(productDto.getName(), productDto.getCategory(), productDto.getPrice()); + return res; + } + + @PutMapping("/{id}") + public ResponseEntity putProduct(@PathVariable int id, @RequestBody ProductCreateDto productDto){ + ResponseEntity res = this.productService.putProduct(id, productDto.getName(), productDto.getCategory(), productDto.getPrice()); + return res; + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteProduct(@PathVariable int id){ + ResponseEntity res = this.productService.deleteProduct(id); + return res; + } + +} diff --git a/src/main/java/com/booleanuk/api/product/model/Product.java b/src/main/java/com/booleanuk/api/product/model/Product.java new file mode 100644 index 0000000..7c81460 --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/model/Product.java @@ -0,0 +1,55 @@ +package com.booleanuk.api.product.model; + +public class Product { + + private static int nextId = 0; + + private int id; + private String name; + private String category; + private int price; + + public Product(String name, String category, int price){ + setId(++nextId); + setName(name); + setCategory(category); + setPrice(price); + } + + public int getId(){ + return this.id; + } + + public void setId(int id){ + this.id = id; + } + + public String getName(){ + return this.name; + } + + public void setName(String name){ + this.name = name; + } + + public String getCategory(){ + return this.category; + } + + public void setCategory(String category){ + this.category = category; + } + + public int getPrice(){ + return this.price; + } + + public void setPrice(int price){ + this.price = price; + } + + public static int getCurrentId(){ + return nextId; + } + +} diff --git a/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java b/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java new file mode 100644 index 0000000..d834bea --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java @@ -0,0 +1,41 @@ + +package com.booleanuk.api.product.model; + +public class ProductCreateDto { + + + private String name; + private String category; + private int price; + + public ProductCreateDto(String name, String category, int price){ + setName(name); + setCategory(category); + setPrice(price); + } + + public String getName(){ + return this.name; + } + + public void setName(String name){ + this.name = name; + } + + public String getCategory(){ + return this.category; + } + + public void setCategory(String category){ + this.category = category; + } + + public int getPrice(){ + return this.price; + } + + public void setPrice(int price){ + this.price = price; + } + +} diff --git a/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java b/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java new file mode 100644 index 0000000..b80c9d3 --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java @@ -0,0 +1,68 @@ +package com.booleanuk.api.product.repo; + +import java.util.List; +import java.util.Optional; +import java.util.ArrayList; + +import org.springframework.stereotype.Repository; + +import com.booleanuk.api.product.model.Product; + +@Repository +public class ProductRepository{ + private List products; + + public ProductRepository(){ + this.products = new ArrayList(); + this.products.add(new Product("How to build APIs", "Book", 1500)); + this.products.add(new Product("Get good at vim", "Paper", 100)); + } + + public List getAll(){ + return this.products; + } + + public Product createProduct(String name, String category, int price){ + Product product = new Product(name, category, price); + this.products.add(product); + return product; + } + + public Optional getOne(int id){ + for (Product p : this.products){ + if(p.getId() == id) + return Optional.of(p); + } + return Optional.empty(); + } + + public Optional putOne(int id, String name, String category, int price){ + for (int i = 0; i < Product.getCurrentId()-1; i++){ + Product p = this.products.get(i); + if(p.getId() == id){ + p.setName(name); + p.setCategory(category); + p.setPrice(price); + return Optional.of(this.products.set(i, p)); + } + } + return Optional.empty(); + } + + public Optional deleteOne(int id){ + for (int i = 0; i < Product.getCurrentId()-1; i++){ + Product p = this.products.get(i); + if(p.getId() == id){ + Product removed = this.products.remove(i); + return Optional.of(removed); + } + } + return Optional.empty(); + } + + public boolean isProduct(String name){ + boolean cond = this.products.stream().anyMatch(product -> product.getName().equals(name)); + return cond; + } + +} diff --git a/src/main/java/com/booleanuk/api/product/service/ProductService.java b/src/main/java/com/booleanuk/api/product/service/ProductService.java new file mode 100644 index 0000000..3a3bbe8 --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/service/ProductService.java @@ -0,0 +1,71 @@ +package com.booleanuk.api.product.service; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import com.booleanuk.api.product.repo.ProductRepository; + +import java.util.List; +import java.util.Optional; + +import com.booleanuk.api.product.model.Product; + +@Service +public class ProductService{ + + private ProductRepository productRepo; + + public ProductService(ProductRepository productRepo){ + this.productRepo = productRepo; + } + + public List getAllProduct(){ + return this.productRepo.getAll(); + } + + public ResponseEntity createProduct(String name, String category, int price){ + if(price < 0) + return ResponseEntity.unprocessableEntity().body(null); + else if(name.isBlank() || category.isBlank()) + return ResponseEntity.unprocessableEntity().body(null); + else if(this.productRepo.isProduct(name)) + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + + Product prod = this.productRepo.createProduct(name, category, price); + + return ResponseEntity.status(HttpStatus.CREATED).body(prod); + } + + public ResponseEntity getProduct(int id){ + Optional optionalProd = this.productRepo.getOne(id); + if(optionalProd.isEmpty()) + return ResponseEntity.notFound().build(); + + return ResponseEntity.ok(optionalProd.get()); + } + + public ResponseEntity putProduct(int id, String name, String category, int price){ + if(price < 0) + return ResponseEntity.unprocessableEntity().body(null); + else if(name.isBlank() || category.isBlank()) + return ResponseEntity.unprocessableEntity().body(null); + else if(this.productRepo.isProduct(name)) + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + + Optional optionalProd = this.productRepo.putOne(id, name, category, price); + if(optionalProd.isEmpty()) + return ResponseEntity.notFound().build(); + + return ResponseEntity.ok(optionalProd.get()); + } + + public ResponseEntity deleteProduct(int id){ + Optional optionalProd = this.productRepo.deleteOne(id); + if(optionalProd.isEmpty()) + return ResponseEntity.notFound().build(); + + return ResponseEntity.ok(optionalProd.get()); + } + +} From 78bd5ebe8b8d0b20b42d5a57a95c3f861d5230d7 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 31 Aug 2026 15:28:14 +0200 Subject: [PATCH 2/3] more proper errorhandleing, did most of extentions --- .../product/controller/ProductController.java | 1 + .../exeption/AlreadyExistsException.java | 7 ++++++ .../exeption/InputNotValidException.java | 7 ++++++ .../exeption/ProductExeptionHandler.java | 25 +++++++++++++++++++ .../exeption/ResourceNotFoundException.java | 7 ++++++ .../api/product/model/ProductCreateDto.java | 1 - .../api/product/service/ProductService.java | 22 +++++++++------- 7 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/booleanuk/api/product/exeption/AlreadyExistsException.java create mode 100644 src/main/java/com/booleanuk/api/product/exeption/InputNotValidException.java create mode 100644 src/main/java/com/booleanuk/api/product/exeption/ProductExeptionHandler.java create mode 100644 src/main/java/com/booleanuk/api/product/exeption/ResourceNotFoundException.java diff --git a/src/main/java/com/booleanuk/api/product/controller/ProductController.java b/src/main/java/com/booleanuk/api/product/controller/ProductController.java index 151c17c..1c81988 100644 --- a/src/main/java/com/booleanuk/api/product/controller/ProductController.java +++ b/src/main/java/com/booleanuk/api/product/controller/ProductController.java @@ -8,6 +8,7 @@ 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.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.booleanuk.api.product.service.ProductService; diff --git a/src/main/java/com/booleanuk/api/product/exeption/AlreadyExistsException.java b/src/main/java/com/booleanuk/api/product/exeption/AlreadyExistsException.java new file mode 100644 index 0000000..da9cfab --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/exeption/AlreadyExistsException.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.product.exeption; + +public class AlreadyExistsException extends RuntimeException{ + public AlreadyExistsException(String message){ + super(message); + } +} diff --git a/src/main/java/com/booleanuk/api/product/exeption/InputNotValidException.java b/src/main/java/com/booleanuk/api/product/exeption/InputNotValidException.java new file mode 100644 index 0000000..130733f --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/exeption/InputNotValidException.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.product.exeption; + +public class InputNotValidException extends RuntimeException{ + public InputNotValidException(String message){ + super(message); + } +} diff --git a/src/main/java/com/booleanuk/api/product/exeption/ProductExeptionHandler.java b/src/main/java/com/booleanuk/api/product/exeption/ProductExeptionHandler.java new file mode 100644 index 0000000..a574402 --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/exeption/ProductExeptionHandler.java @@ -0,0 +1,25 @@ +package com.booleanuk.api.product.exeption; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ProductExeptionHandler{ + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleNotFound(ResourceNotFoundException ex){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); + } + + @ExceptionHandler(AlreadyExistsException.class) + public ResponseEntity handleInvalidRequest(AlreadyExistsException ex){ + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } + + @ExceptionHandler(InputNotValidException.class) + public ResponseEntity handleInvelidArgs(InputNotValidException ex){ + return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(ex.getMessage()); + } +} diff --git a/src/main/java/com/booleanuk/api/product/exeption/ResourceNotFoundException.java b/src/main/java/com/booleanuk/api/product/exeption/ResourceNotFoundException.java new file mode 100644 index 0000000..8f43b75 --- /dev/null +++ b/src/main/java/com/booleanuk/api/product/exeption/ResourceNotFoundException.java @@ -0,0 +1,7 @@ +package com.booleanuk.api.product.exeption; + +public class ResourceNotFoundException extends RuntimeException{ + public ResourceNotFoundException(String message){ + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java b/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java index d834bea..612349f 100644 --- a/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java +++ b/src/main/java/com/booleanuk/api/product/model/ProductCreateDto.java @@ -1,4 +1,3 @@ - package com.booleanuk.api.product.model; public class ProductCreateDto { diff --git a/src/main/java/com/booleanuk/api/product/service/ProductService.java b/src/main/java/com/booleanuk/api/product/service/ProductService.java index 3a3bbe8..794cedc 100644 --- a/src/main/java/com/booleanuk/api/product/service/ProductService.java +++ b/src/main/java/com/booleanuk/api/product/service/ProductService.java @@ -5,6 +5,10 @@ import org.springframework.stereotype.Service; import com.booleanuk.api.product.repo.ProductRepository; +import com.booleanuk.api.product.exeption.ResourceNotFoundException; +import com.booleanuk.api.product.exeption.InputNotValidException; +import com.booleanuk.api.product.exeption.AlreadyExistsException; + import java.util.List; import java.util.Optional; @@ -26,11 +30,11 @@ public List getAllProduct(){ public ResponseEntity createProduct(String name, String category, int price){ if(price < 0) - return ResponseEntity.unprocessableEntity().body(null); + throw new InputNotValidException("Price cannot be negative"); else if(name.isBlank() || category.isBlank()) - return ResponseEntity.unprocessableEntity().body(null); + throw new InputNotValidException("Cannot be empty or blank"); else if(this.productRepo.isProduct(name)) - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + throw new AlreadyExistsException("Product with name allready exists"); Product prod = this.productRepo.createProduct(name, category, price); @@ -40,22 +44,22 @@ else if(this.productRepo.isProduct(name)) public ResponseEntity getProduct(int id){ Optional optionalProd = this.productRepo.getOne(id); if(optionalProd.isEmpty()) - return ResponseEntity.notFound().build(); + throw new ResourceNotFoundException("Product not found"); return ResponseEntity.ok(optionalProd.get()); } public ResponseEntity putProduct(int id, String name, String category, int price){ if(price < 0) - return ResponseEntity.unprocessableEntity().body(null); + throw new InputNotValidException("Price cannot be negative"); else if(name.isBlank() || category.isBlank()) - return ResponseEntity.unprocessableEntity().body(null); + throw new InputNotValidException("Cannot be empty or blank"); else if(this.productRepo.isProduct(name)) - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + throw new AlreadyExistsException("Product with name allready exists"); Optional optionalProd = this.productRepo.putOne(id, name, category, price); if(optionalProd.isEmpty()) - return ResponseEntity.notFound().build(); + throw new ResourceNotFoundException("Product not found"); return ResponseEntity.ok(optionalProd.get()); } @@ -63,7 +67,7 @@ else if(this.productRepo.isProduct(name)) public ResponseEntity deleteProduct(int id){ Optional optionalProd = this.productRepo.deleteOne(id); if(optionalProd.isEmpty()) - return ResponseEntity.notFound().build(); + throw new ResourceNotFoundException("Product not found"); return ResponseEntity.ok(optionalProd.get()); } From 30cce715bcd37a6ae62435185c779cf5bfe9631a Mon Sep 17 00:00:00 2001 From: David Date: Tue, 1 Sep 2026 08:56:13 +0200 Subject: [PATCH 3/3] fixed extentions --- .../product/controller/ProductController.java | 32 +++++++++++++------ .../api/product/repo/ProductRepository.java | 11 +++++++ .../api/product/service/ProductService.java | 24 +++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/booleanuk/api/product/controller/ProductController.java b/src/main/java/com/booleanuk/api/product/controller/ProductController.java index 1c81988..e7409a7 100644 --- a/src/main/java/com/booleanuk/api/product/controller/ProductController.java +++ b/src/main/java/com/booleanuk/api/product/controller/ProductController.java @@ -1,5 +1,6 @@ package com.booleanuk.api.product.controller; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -26,34 +27,45 @@ public ProductController(ProductService productService){ this.productService = productService; } + // @GetMapping + // public ResponseEntity> getAllProduct(){ + // List prods = this.productService.getAllProduct(); + // return ResponseEntity.ok(prods); + // } + @GetMapping - public ResponseEntity> getAllProduct(){ - List prods = this.productService.getAllProduct(); + public ResponseEntity> getAllProduct(@RequestParam (required = false) String category){ + List prods; + if(category == null) + prods = this.productService.getAllProduct(); + else + prods = this.productService.getAllProduct(category); + return ResponseEntity.ok(prods); } @GetMapping("/{id}") public ResponseEntity getProduct(@PathVariable int id){ - ResponseEntity res = this.productService.getProduct(id); - return res; + Product res = this.productService.getProduct(id); + return ResponseEntity.ok(res); } @PostMapping public ResponseEntity createProduct(@RequestBody ProductCreateDto productDto){ - ResponseEntity res = this.productService.createProduct(productDto.getName(), productDto.getCategory(), productDto.getPrice()); - return res; + Product res = this.productService.createProduct(productDto.getName(), productDto.getCategory(), productDto.getPrice()); + return ResponseEntity.status(HttpStatus.CREATED).body(res); } @PutMapping("/{id}") public ResponseEntity putProduct(@PathVariable int id, @RequestBody ProductCreateDto productDto){ - ResponseEntity res = this.productService.putProduct(id, productDto.getName(), productDto.getCategory(), productDto.getPrice()); - return res; + Product res = this.productService.putProduct(id, productDto.getName(), productDto.getCategory(), productDto.getPrice()); + return ResponseEntity.ok(res); } @DeleteMapping("/{id}") public ResponseEntity deleteProduct(@PathVariable int id){ - ResponseEntity res = this.productService.deleteProduct(id); - return res; + Product res = this.productService.deleteProduct(id); + return ResponseEntity.ok(res); } } diff --git a/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java b/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java index b80c9d3..982ecb6 100644 --- a/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java +++ b/src/main/java/com/booleanuk/api/product/repo/ProductRepository.java @@ -22,6 +22,17 @@ public List getAll(){ return this.products; } + public Optional> getAll(String category){ + List tmp = new ArrayList(); + for (Product p : this.products){ + if(p.getCategory().equals(category)) + tmp.add(p); + } + if(tmp.isEmpty()) + return Optional.empty(); + return Optional.of(tmp); + } + public Product createProduct(String name, String category, int price){ Product product = new Product(name, category, price); this.products.add(product); diff --git a/src/main/java/com/booleanuk/api/product/service/ProductService.java b/src/main/java/com/booleanuk/api/product/service/ProductService.java index 794cedc..5c369ed 100644 --- a/src/main/java/com/booleanuk/api/product/service/ProductService.java +++ b/src/main/java/com/booleanuk/api/product/service/ProductService.java @@ -28,7 +28,15 @@ public List getAllProduct(){ return this.productRepo.getAll(); } - public ResponseEntity createProduct(String name, String category, int price){ + public List getAllProduct(String category){ + Optional> res = this.productRepo.getAll(category); + if(res.isEmpty()) + throw new ResourceNotFoundException("No category called \"" + category + "\""); + + return res.get(); + } + + public Product createProduct(String name, String category, int price){ if(price < 0) throw new InputNotValidException("Price cannot be negative"); else if(name.isBlank() || category.isBlank()) @@ -38,18 +46,18 @@ else if(this.productRepo.isProduct(name)) Product prod = this.productRepo.createProduct(name, category, price); - return ResponseEntity.status(HttpStatus.CREATED).body(prod); + return prod; } - public ResponseEntity getProduct(int id){ + public Product getProduct(int id){ Optional optionalProd = this.productRepo.getOne(id); if(optionalProd.isEmpty()) throw new ResourceNotFoundException("Product not found"); - return ResponseEntity.ok(optionalProd.get()); + return optionalProd.get(); } - public ResponseEntity putProduct(int id, String name, String category, int price){ + public Product putProduct(int id, String name, String category, int price){ if(price < 0) throw new InputNotValidException("Price cannot be negative"); else if(name.isBlank() || category.isBlank()) @@ -61,15 +69,15 @@ else if(this.productRepo.isProduct(name)) if(optionalProd.isEmpty()) throw new ResourceNotFoundException("Product not found"); - return ResponseEntity.ok(optionalProd.get()); + return optionalProd.get(); } - public ResponseEntity deleteProduct(int id){ + public Product deleteProduct(int id){ Optional optionalProd = this.productRepo.deleteOne(id); if(optionalProd.isEmpty()) throw new ResourceNotFoundException("Product not found"); - return ResponseEntity.ok(optionalProd.get()); + return optionalProd.get(); } }