deprecated ‐ 2. Product Catalog Service‐Mongodb Edition‐ step‐by‐step guide - Wiz-DevTech/prettygirllz GitHub Wiki
Here's a comprehensive step-by-step guide for implementing the Product Catalog Service in Java with MongoDB, Maven, and full testing integration:
(Visual representation of the components we'll build)
# Java JDK 17
sudo apt install openjdk-17-jdk
# Maven
sudo apt install maven
# MongoDB (Docker)
docker run -d -p 27017:27017 --name mongodb -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=secret mongo:6.0
# IDE (Optional)
sudo snap install intellij-idea-ultimate --classic
java -version # Should show 17+
mvn -v # Should show 3.8+
docker ps # Should show MongoDB running
mvn archetype:generate -DgroupId=com.productcatalog -DartifactId=product-service -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd product-service
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
// src/main/java/com/productcatalog/model/Product.java
package com.productcatalog.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "products")
public class Product {
@Id
private String id;
private String sku; // Format: ABC-1234
private String name;
private int inventory;
// Constructors, Getters, Setters
}
// src/main/java/com/productcatalog/repository/ProductRepository.java
package com.productcatalog.repository;
import com.productcatalog.model.Product;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface ProductRepository extends MongoRepository<Product, String> {
Product findBySku(String sku);
}
// src/main/java/com/productcatalog/service/ProductService.java
package com.productcatalog.service;
import com.productcatalog.exception.InvalidSKUException;
import com.productcatalog.model.Product;
import com.productcatalog.repository.ProductRepository;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
private final ProductRepository repository;
public ProductService(ProductRepository repository) {
this.repository = repository;
}
public Product createProduct(Product product) throws InvalidSKUException {
if (!product.getSku().matches("^[A-Z]{3}-\\d{4}$")) {
throw new InvalidSKUException("SKU must match format ABC-1234");
}
return repository.save(product);
}
}
// src/main/java/com/productcatalog/controller/ProductController.java
package com.productcatalog.controller;
import com.productcatalog.exception.InvalidSKUException;
import com.productcatalog.model.Product;
import com.productcatalog.service.ProductService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) throws InvalidSKUException {
return ResponseEntity.ok(productService.createProduct(product));
}
}
// src/test/java/com/productcatalog/service/ProductServiceTest.java
package com.productcatalog.service;
import com.productcatalog.exception.InvalidSKUException;
import com.productcatalog.model.Product;
import com.productcatalog.repository.ProductRepository;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@SpringBootTest
class ProductServiceTest {
@Mock
private ProductRepository repository;
@InjectMocks
private ProductService productService;
@Test
void whenInvalidSKU_thenThrowsException() {
Product product = new Product("INVALID", "Test Product", 10);
assertThrows(InvalidSKUException.class, () -> productService.createProduct(product));
}
}
// src/test/java/com/productcatalog/ProductIntegrationTest.java
package com.productcatalog;
import com.productcatalog.model.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@DataMongoTest
class ProductIntegrationTest {
@Autowired
private MongoTemplate mongoTemplate;
@Test
void whenSaveProduct_thenCanRetrieve() {
Product product = new Product("ABC-1234", "Test Product", 10);
mongoTemplate.save(product);
Product found = mongoTemplate.findById(product.getId(), Product.class);
assertThat(found.getSku()).isEqualTo(product.getSku());
}
}
// src/test/java/com/productcatalog/controller/ProductControllerTest.java
package com.productcatalog.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.productcatalog.model.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void whenValidInput_thenReturns200() throws Exception {
Product product = new Product("ABC-1234", "Test Product", 10);
mockMvc.perform(post("/api/products")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(product)))
.andExpect(status().isOk());
}
}
mvn spring-boot:run
# Create Product
curl -X POST http://localhost:8080/api/products \
-H "Content-Type: application/json" \
-d '{"sku":"ABC-1234","name":"Sample Product","inventory":10}'
# Verify in MongoDB
docker exec -it mongodb mongosh -u admin -p secret
> use productcatalog
> db.products.find()
mvn test
mvn clean package
# Dockerfile
FROM eclipse-temurin:17-jdk
COPY target/product-service-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
Build and run:
docker build -t product-service .
docker run -p 8080:8080 --link mongodb product-service
Issue | Solution |
---|---|
MongoDB connection refused | Verify credentials in application.properties
|
Tests fail with port conflict | Add @TestPropertySource(properties = "spring.mongodb.embedded.version=6.0.5")
|
Invalid SKU not caught | Check regex pattern in ProductService
|
- Add Swagger UI for API documentation
- Implement JWT Authentication
- Set up CI/CD Pipeline (Jenkins/GitHub Actions)
Let me know if you'd like me to expand any section! 🚀