Create a directory named dto and a new file named ProductDto within it.

Define the ProductDTO as follows:
public record ProductDto(
String id, String name, String code, float price, String model,
@JsonInclude(JsonInclude.Include.NON_NULL)
String url
) {
public ProductDto(Product product) {
this(product.getId(), product.getProductName(), product.getCode(),
product.getPrice(), product.getModel(), product.getProductUrl());
}
static public Product toProduct(ProductDto productDto) {
Product product = new Product();
product.setId(product.getId());
product.setProductName(productDto.name);
product.setCode(productDto.code());
product.setModel(productDto.model());
product.setPrice(productDto.price());
product.setProductUrl(productDto.url());
return product;
}
}

ProductsController class, initialize productsRepository:
productsRepository as a dependency injection through the constructor, used to access data from products in the database.productsRepository in the constructor using @Autowired, allowing Spring to automatically inject productsRepository into the controller. private final ProductsRepository productsRepository;
@Autowired
public ProductsController(ProductsRepository productsRepository) {
this.productsRepository = productsRepository;
}

Create the getAllProducts method. This method is annotated with @GetMapping, indicating that it handles HTTP GET requests to the specified path (/products). The method includes:
productsDto to store ProductDto objects.productsRepository.getAll().items().subscribe(...) to retrieve a list of products from the repository.ProductDto and adds it to productsDto.ResponseEntity<List<ProductDto>> containing the created productsDto list with an HTTP status of HttpStatus.OK.@GetMapping
public ResponseEntity<List<ProductDto>> getAllProducts() {
LOG.info("Get all products");
List<ProductDto> productsDto = new ArrayList<>();
productsRepository.getAll().items().subscribe(product -> {
productsDto.add(new ProductDto(product));
}).join();
return new ResponseEntity<>(productsDto, HttpStatus.OK);
}

5. Create the **getProductById** method. This method is annotated with **@GetMapping("{id}")**, indicating that it handles HTTP GET requests to "/products/{id}", where `{id}` is a path variable.
- This method retrieves the `id` from the path and uses `productsRepository.getById(id).join()` to wait for and retrieve the `Product` from the repository.
- If the `product` is not `null`, it returns the `ProductDto` of that product with an HTTP status of `HttpStatus.OK`.
- If the `product` is `null`, it returns an error message "Product not found" with an HTTP status of `HttpStatus.NOT_FOUND`.
```java
@GetMapping("{id}")
public ResponseEntity<?> getProductById(@PathVariable("id") String id) {
Product product = productsRepository.getById(id).join();
if (product != null) {
return new ResponseEntity<>(new ProductDto(product), HttpStatus.OK);
} else {
return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND);
}
}

Create the createProduct method. This method is annotated with @PostMapping, indicating that it handles HTTP POST requests to “/products”.
productDto), assigns a new id using UUID.randomUUID().toString(), and then saves productCreated to productsRepository using productsRepository.create(productCreated).join(). @PostMapping
public ResponseEntity<ProductDto> createProduct(@RequestBody ProductDto productDto) {
Product productCreated = ProductDto.toProduct(productDto);
productCreated.setId(UUID.randomUUID().toString());
productsRepository.create(productCreated).join();
LOG.info("Product created - ID: {}", productCreated.getId());
return new ResponseEntity<>(new ProductDto(productCreated), HttpStatus.CREATED);
}

Create the deleteProductById method. This method is annotated with @DeleteMapping("{id}"), indicating that it handles HTTP DELETE requests to “/products/{id}”.
@DeleteMapping("{id}")
public ResponseEntity<?> deleteProductById(@PathVariable("id") String id) {
Product productDeleted = productsRepository.deleteById(id).join();
if (productDeleted != null) {
LOG.info("Product deleted - ID: {}", productDeleted.getId());
return new ResponseEntity<>(new ProductDto(productDeleted), HttpStatus.OK);
} else {
return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND);
}
}

Create the updateProduct method. This method is annotated with @PutMapping("{id}"), indicating that it handles HTTP PUT requests to “/products/{id}”.
@PutMapping("{id}")
public ResponseEntity<?> updateProduct(@RequestBody ProductDto productDto,
@PathVariable("id") String id) {
try {
Product productUpdated = productsRepository
.update(ProductDto.toProduct(productDto), id).join();
LOG.info("Product updated - ID: {}", productUpdated.getId());
return new ResponseEntity<>(new ProductDto(productUpdated), HttpStatus.OK);
} catch (CompletionException e) {
return new ResponseEntity<>("Product not found", HttpStatus.NOT_FOUND);
}
}
