ProductController
is the implementation of the main Product Endpoint API
+ * definition.
+ *
+ * @see ProductEndpoint
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RestController
+@Log4j2
+public class ProductController implements ProductEndpoint {
+
+ /** Product service business logic interface. */
+ private final ProductService prodService;
+
+ @Autowired
+ public ProductController(@Qualifier("ProductServiceImpl") ProductService prodService) {
+ this.prodService = prodService;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Product getProduct(int id) {
+ return prodService.getProduct(id);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Product createProduct(Product body) {
+ return prodService.createProduct(body);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void deleteProduct(int id) {
+ prodService.deleteProduct(id);
+ }
+}
diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductServiceImpl.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductServiceImpl.java
deleted file mode 100644
index c2152311..00000000
--- a/product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductServiceImpl.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.siriusxi.ms.store.ps.controller;
-
-import com.mongodb.DuplicateKeyException;
-import com.siriusxi.ms.store.api.core.product.Product;
-import com.siriusxi.ms.store.api.core.product.ProductService;
-import com.siriusxi.ms.store.ps.persistence.ProductEntity;
-import com.siriusxi.ms.store.ps.persistence.ProductRepository;
-import com.siriusxi.ms.store.util.exceptions.InvalidInputException;
-import com.siriusxi.ms.store.util.exceptions.NotFoundException;
-import com.siriusxi.ms.store.util.http.ServiceUtil;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@Log4j2
-public class ProductServiceImpl implements ProductService {
-
- private final ServiceUtil serviceUtil;
-
- private final ProductRepository repository;
-
- private final ProductMapper mapper;
-
- @Autowired
- public ProductServiceImpl(ProductRepository repository,
- ProductMapper mapper,
- ServiceUtil serviceUtil) {
- this.repository = repository;
- this.mapper = mapper;
- this.serviceUtil = serviceUtil;
- }
-
- @Override
- public Product createProduct(Product body) {
- try {
- ProductEntity entity = mapper.apiToEntity(body);
- ProductEntity newEntity = repository.save(entity);
-
- log.debug("createProduct: entity created for productId: {}", body.getProductId());
- return mapper.entityToApi(newEntity);
-
- } catch (DuplicateKeyException dke) {
- throw new InvalidInputException("Duplicate key, Product Id: " + body.getProductId());
- }
- }
-
- @Override
- public Product getProduct(int productId) {
- if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId);
-
- ProductEntity entity = repository.findByProductId(productId)
- .orElseThrow(() -> new NotFoundException("No product found for productId: " + productId));
-
- Product response = mapper.entityToApi(entity);
- response.setServiceAddress(serviceUtil.getServiceAddress());
-
- log.debug("getProduct: found productId: {}", response.getProductId());
-
- return response;
- }
-
- @Override
- public void deleteProduct(int productId) {
- log.debug("deleteProduct: tries to delete an entity with productId: {}", productId);
- repository.findByProductId(productId).ifPresent(repository::delete);
- }
-}
diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductMapper.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductMapper.java
similarity index 83%
rename from product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductMapper.java
rename to product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductMapper.java
index 25a34994..d0834c49 100644
--- a/product-service/src/main/java/com/siriusxi/ms/store/ps/controller/ProductMapper.java
+++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductMapper.java
@@ -1,6 +1,6 @@
-package com.siriusxi.ms.store.ps.controller;
+package com.siriusxi.ms.store.ps.service;
-import com.siriusxi.ms.store.api.core.product.Product;
+import com.siriusxi.ms.store.api.core.product.dto.Product;
import com.siriusxi.ms.store.ps.persistence.ProductEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java
new file mode 100644
index 00000000..03dce467
--- /dev/null
+++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java
@@ -0,0 +1,74 @@
+package com.siriusxi.ms.store.ps.service;
+
+import com.siriusxi.ms.store.api.core.product.ProductService;
+import com.siriusxi.ms.store.api.core.product.dto.Product;
+import com.siriusxi.ms.store.ps.persistence.ProductEntity;
+import com.siriusxi.ms.store.ps.persistence.ProductRepository;
+import com.siriusxi.ms.store.util.exceptions.InvalidInputException;
+import com.siriusxi.ms.store.util.exceptions.NotFoundException;
+import com.siriusxi.ms.store.util.http.ServiceUtil;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+@Service("ProductServiceImpl")
+@Log4j2
+public class ProductServiceImpl implements ProductService {
+
+ private final ServiceUtil serviceUtil;
+
+ private final ProductRepository repository;
+
+ private final ProductMapper mapper;
+
+ @Autowired
+ public ProductServiceImpl(
+ ProductRepository repository, ProductMapper mapper, ServiceUtil serviceUtil) {
+ this.repository = repository;
+ this.mapper = mapper;
+ this.serviceUtil = serviceUtil;
+ }
+
+ @Override
+ public Product createProduct(Product body) {
+ try {
+ ProductEntity entity = mapper.apiToEntity(body);
+ ProductEntity newEntity = repository.save(entity);
+
+ log.debug("createProduct: entity created for productId: {}", body.getProductId());
+ return mapper.entityToApi(newEntity);
+
+ } catch (DuplicateKeyException dke) {
+ throw new InvalidInputException("Duplicate key, Product Id: " + body.getProductId());
+ }
+ }
+
+ @Override
+ public Product getProduct(int productId) {
+ if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId);
+
+ ProductEntity entity =
+ repository
+ .findByProductId(productId)
+ .orElseThrow(
+ () -> new NotFoundException("No product found for productId: " + productId));
+
+ Product response = mapper.entityToApi(entity);
+ response.setServiceAddress(serviceUtil.getServiceAddress());
+
+ log.debug("getProduct: found productId: {}", response.getProductId());
+
+ return response;
+ }
+
+ /*
+ Implementation is idempotent, that is,
+ it will not report any failure if the entity is not found Always 200
+ */
+ @Override
+ public void deleteProduct(int productId) {
+ log.debug("deleteProduct: tries to delete an entity with productId: {}", productId);
+ repository.findByProductId(productId).ifPresent(repository::delete);
+ }
+}
diff --git a/product-service/src/main/resources/application.yaml b/product-service/src/main/resources/application.yaml
index 0c7cdc9d..11a6c7ba 100644
--- a/product-service/src/main/resources/application.yaml
+++ b/product-service/src/main/resources/application.yaml
@@ -6,7 +6,8 @@ spring:
host: localhost
port: 27017
database: product-db
-
+ auto-index-creation: true
+
server:
port: 9081
@@ -39,4 +40,4 @@ spring:
host: mongodb
server:
- port: 8080
\ No newline at end of file
+ port: 8080
diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java
index 7933fd07..0d0ee1cc 100644
--- a/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java
+++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java
@@ -1,7 +1,7 @@
package com.siriusxi.ms.store.ps;
-import com.siriusxi.ms.store.api.core.product.Product;
-import com.siriusxi.ms.store.ps.controller.ProductMapper;
+import com.siriusxi.ms.store.api.core.product.dto.Product;
+import com.siriusxi.ms.store.ps.service.ProductMapper;
import com.siriusxi.ms.store.ps.persistence.ProductEntity;
import org.junit.jupiter.api.Test;
@@ -9,7 +9,7 @@
public class MapperTests {
- private final ProductMapper mapper = ProductMapper.INSTANCE;
+ private final ProductMapper mapper = ProductMapper.INSTANCE;
@Test
public void mapperTests() {
diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java
index 87f5deb6..6996252e 100644
--- a/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java
+++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java
@@ -4,7 +4,6 @@
import com.siriusxi.ms.store.ps.persistence.ProductRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
@@ -76,9 +75,7 @@ public void getByProductId() {
assertEqualsProduct(savedEntity, entity.get());
}
- //FIXME error which is not thrown
@Test
- @Disabled
public void duplicateError() {
Assertions.assertThrows(
diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java
index ce7f24e1..e8c7af7e 100644
--- a/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java
+++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java
@@ -1,9 +1,8 @@
package com.siriusxi.ms.store.ps;
-import com.siriusxi.ms.store.api.core.product.Product;
+import com.siriusxi.ms.store.api.core.product.dto.Product;
import com.siriusxi.ms.store.ps.persistence.ProductRepository;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@@ -17,126 +16,140 @@
import static org.springframework.http.HttpStatus.*;
import static org.springframework.http.MediaType.APPLICATION_JSON;
-@SpringBootTest(webEnvironment= RANDOM_PORT, properties = {"spring.data.mongodb.port: 0"})
+@SpringBootTest(
+ webEnvironment = RANDOM_PORT,
+ properties = {"spring.data.mongodb.port: 0"})
class ProductServiceApplicationTests {
- private final String BASE_URI = "/products/";
+ private final String BASE_URI = "/products/";
- @Autowired
- private WebTestClient client;
+ @Autowired private WebTestClient client;
- @Autowired
- private ProductRepository repository;
+ @Autowired private ProductRepository repository;
- @BeforeEach
- public void setupDb() {
- repository.deleteAll();
- }
+ @BeforeEach
+ public void setupDb() {
+ repository.deleteAll();
+ }
+ @Test
+ public void getProductById() {
- @Test
- public void getProductById() {
+ int productId = 1;
- int productId = 1;
-
- postAndVerifyProduct(productId, OK);
-
- assertTrue(repository.findByProductId(productId).isPresent());
-
- getAndVerifyProduct(productId, OK)
- .jsonPath("$.productId").isEqualTo(productId);
- }
-
- @Test
- @Disabled
- public void duplicateError() {
-
- int productId = 1;
-
- postAndVerifyProduct(productId, OK);
-
- assertTrue(repository.findByProductId(productId).isPresent());
-
- postAndVerifyProduct(productId, UNPROCESSABLE_ENTITY)
- .jsonPath("$.path").isEqualTo("BASE_RESOURCE_URI")
- .jsonPath("$.message").isEqualTo("Duplicate key, Product Id: " + productId);
- }
-
- @Test
- public void deleteProduct() {
-
- int productId = 1;
-
- postAndVerifyProduct(productId, OK);
- assertTrue(repository.findByProductId(productId).isPresent());
-
- deleteAndVerifyProduct(productId, OK);
- assertFalse(repository.findByProductId(productId).isPresent());
-
- deleteAndVerifyProduct(productId, OK);
- }
-
- @Test
- public void getProductInvalidParameterString() {
-
- getAndVerifyProduct(BASE_URI + "/no-integer", BAD_REQUEST)
- .jsonPath("$.path").isEqualTo(BASE_URI + "no-integer")
- .jsonPath("$.message").isEqualTo("Type mismatch.");
- }
-
- @Test
- public void getProductNotFound() {
-
- int productIdNotFound = 13;
- getAndVerifyProduct(productIdNotFound, NOT_FOUND)
- .jsonPath("$.path").isEqualTo(BASE_URI + productIdNotFound)
- .jsonPath("$.message").isEqualTo("No product found for productId: " + productIdNotFound);
- }
-
- @Test
- public void getProductInvalidParameterNegativeValue() {
-
- int productIdInvalid = -1;
-
- getAndVerifyProduct(productIdInvalid, UNPROCESSABLE_ENTITY)
- .jsonPath("$.path").isEqualTo(BASE_URI + productIdInvalid)
- .jsonPath("$.message").isEqualTo("Invalid productId: " + productIdInvalid);
- }
-
-
- private WebTestClient.BodyContentSpec getAndVerifyProduct(int productId, HttpStatus expectedStatus) {
- return getAndVerifyProduct(BASE_URI + productId, expectedStatus);
- }
-
- private WebTestClient.BodyContentSpec getAndVerifyProduct(String productIdPath, HttpStatus expectedStatus) {
- return client.get()
- .uri(productIdPath)
- .accept(APPLICATION_JSON)
- .exchange()
- .expectStatus().isEqualTo(expectedStatus)
- .expectHeader().contentType(APPLICATION_JSON)
- .expectBody();
- }
-
- private WebTestClient.BodyContentSpec postAndVerifyProduct(int productId, HttpStatus expectedStatus) {
- Product product = new Product(productId, "Name " + productId, productId, "SA");
- return client.post()
- .uri(BASE_URI)
- .body(Mono.just(product), Product.class)
- .accept(APPLICATION_JSON)
- .exchange()
- .expectStatus().isEqualTo(expectedStatus)
- .expectHeader().contentType(APPLICATION_JSON)
- .expectBody();
- }
-
- private WebTestClient.BodyContentSpec deleteAndVerifyProduct(int productId, HttpStatus expectedStatus) {
- return client.delete()
- .uri(BASE_URI + productId)
- .accept(APPLICATION_JSON)
- .exchange()
- .expectStatus().isEqualTo(expectedStatus)
- .expectBody();
- }
+ postAndVerifyProduct(productId, OK);
+ assertTrue(repository.findByProductId(productId).isPresent());
+
+ getAndVerifyProduct(productId, OK).jsonPath("$.productId").isEqualTo(productId);
+ }
+
+ @Test
+ public void duplicateError() {
+
+ int productId = 1;
+
+ postAndVerifyProduct(productId, OK);
+
+ assertTrue(repository.findByProductId(productId).isPresent());
+
+ postAndVerifyProduct(productId, UNPROCESSABLE_ENTITY)
+ .jsonPath("$.path")
+ .isEqualTo(BASE_URI)
+ .jsonPath("$.message")
+ .isEqualTo("Duplicate key, Product Id: " + productId);
+ }
+
+ @Test
+ public void deleteProduct() {
+
+ int productId = 1;
+
+ postAndVerifyProduct(productId, OK);
+ assertTrue(repository.findByProductId(productId).isPresent());
+
+ deleteAndVerifyProduct(productId);
+ assertFalse(repository.findByProductId(productId).isPresent());
+
+ deleteAndVerifyProduct(productId);
+ }
+
+ @Test
+ public void getProductInvalidParameterString() {
+
+ getAndVerifyProduct(BASE_URI + "/no-integer", BAD_REQUEST)
+ .jsonPath("$.path")
+ .isEqualTo(BASE_URI + "no-integer")
+ .jsonPath("$.message")
+ .isEqualTo("Type mismatch.");
+ }
+
+ @Test
+ public void getProductNotFound() {
+
+ int productIdNotFound = 13;
+ getAndVerifyProduct(productIdNotFound, NOT_FOUND)
+ .jsonPath("$.path")
+ .isEqualTo(BASE_URI + productIdNotFound)
+ .jsonPath("$.message")
+ .isEqualTo("No product found for productId: " + productIdNotFound);
+ }
+
+ @Test
+ public void getProductInvalidParameterNegativeValue() {
+
+ int productIdInvalid = -1;
+
+ getAndVerifyProduct(productIdInvalid, UNPROCESSABLE_ENTITY)
+ .jsonPath("$.path")
+ .isEqualTo(BASE_URI + productIdInvalid)
+ .jsonPath("$.message")
+ .isEqualTo("Invalid productId: " + productIdInvalid);
+ }
+
+ private WebTestClient.BodyContentSpec getAndVerifyProduct(
+ int productId, HttpStatus expectedStatus) {
+ return getAndVerifyProduct(BASE_URI + productId, expectedStatus);
+ }
+
+ private WebTestClient.BodyContentSpec getAndVerifyProduct(
+ String productIdPath, HttpStatus expectedStatus) {
+ return client
+ .get()
+ .uri(productIdPath)
+ .accept(APPLICATION_JSON)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(expectedStatus)
+ .expectHeader()
+ .contentType(APPLICATION_JSON)
+ .expectBody();
+ }
+
+ private WebTestClient.BodyContentSpec postAndVerifyProduct(
+ int productId, HttpStatus expectedStatus) {
+ Product product = new Product(productId, "Name " + productId, productId, "SA");
+ return client
+ .post()
+ .uri(BASE_URI)
+ .body(Mono.just(product), Product.class)
+ .accept(APPLICATION_JSON)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(expectedStatus)
+ .expectHeader()
+ .contentType(APPLICATION_JSON)
+ .expectBody();
+ }
+
+ private void deleteAndVerifyProduct(int productId) {
+ client
+ .delete()
+ .uri(BASE_URI + productId)
+ .accept(APPLICATION_JSON)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(OK)
+ .expectBody();
+ }
}
diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java
new file mode 100644
index 00000000..a96f96a1
--- /dev/null
+++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java
@@ -0,0 +1,51 @@
+package com.siriusxi.ms.store.rs.api;
+
+import com.siriusxi.ms.store.api.core.recommendation.RecommendationEndpoint;
+import com.siriusxi.ms.store.api.core.recommendation.RecommendationService;
+import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * Class RecommendationController
is the implementation of the main Recommendation
+ * Endpoint API definition.
+ *
+ * @see RecommendationEndpoint
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RestController
+@Log4j2
+public class RecommendationController implements RecommendationEndpoint {
+ /** Recommendation service business logic interface. */
+ private final RecommendationService recommendationService;
+
+ @Autowired
+ public RecommendationController(
+ @Qualifier("RecommendationServiceImpl") RecommendationService recommendationService) {
+ this.recommendationService = recommendationService;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ListReviewController
is the implementation of the main Review Endpoint API
+ * definition.
+ *
+ * @see ProductEndpoint
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RestController
+@Log4j2
+public class ReviewController implements ReviewEndpoint {
+
+ /** Review service business logic interface. */
+ private final ReviewService reviewService;
+
+ @Autowired
+ public ReviewController(@Qualifier("ReviewServiceImpl") ReviewService reviewService) {
+ this.reviewService = reviewService;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Review createReview(Review body) {
+ return reviewService.createReview(body);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ListStoreEndpoint
is a higher level Interface
+ * to define Store Service endpoint APIs that follow StoreService
+ * interface. And to be implemented by service controllers.
+ *
+ *
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@Api("REST API for Springy Store products information.")
+@RequestMapping("store/api/v1")
+public interface StoreEndpoint extends StoreService {
+
+ /**
+ * Sample usage:
+ *
+ * curl $HOST:$PORT/store/api/v1/products/1
curl -X POST $HOST:$PORT/store/api/v1/products \
+ * -H "Content-Type: application/json" --data \
+ * '{"productId":123,"name":"product 123", "weight":123}'
curl -X DELETE $HOST:$PORT/store/api/v1/products/1
curl -X POST $HOST:$PORT/store/api/v1/products \ - * -H "Content-Type: application/json" --data \ - * '{"productId":123,"name":"product 123", "weight":123}' - * - * @param body of product elements definition. - */ - @ApiOperation( - value = "${api.product-composite.create-composite-product.description}", - notes = "${api.product-composite.create-composite-product.notes}") - @ApiResponses( - value = { - @ApiResponse( - code = 400, - message = """ - Bad Request, invalid format of the request. - See response message for more information. - """), - @ApiResponse( - code = 422, - message = """ - Unprocessable entity, input parameters caused the processing to fail. - See response message for more information. - """) - }) - @PostMapping( - value = "products", - consumes = APPLICATION_JSON_VALUE) - void createProduct(@RequestBody ProductAggregate body); + /** + * Get the aggregate product with its reviews and recommendations and services involved in + * the call. + * + * @see ProductAggregate + * @param id is the product id that you are looking for. + * @return the product, if found, else null. + * @since v0.1 + */ + ProductAggregate getProduct(int id); - /** - * Sample usage: - * - *
curl -X DELETE $HOST:$PORT/store/api/v1/products/1
- *
- * @param productId to delete.
- */
- @ApiOperation(
- value = "${api.product-composite.delete-composite-product.description}",
- notes = "${api.product-composite.delete-composite-product.notes}")
- @ApiResponses(
- value = {
- @ApiResponse(
- code = 400,
- message ="""
- Bad Request, invalid format of the request.
- See response message for more information.
- """),
- @ApiResponse(
- code = 422,
- message ="""
- Unprocessable entity, input parameters caused the processing to fail.
- See response message for more information.
- """)
- })
- @DeleteMapping("products/{productId}")
- void deleteProduct(@PathVariable int productId);
+ /**
+ * Delete the product and all its relate reviews and recommendations from their repositories.
+ *
+ * @see ProductAggregate
+ * @implNote This method should be idempotent and always return 200 OK status.
+ * @param id to be deleted.
+ * @since v0.1
+ */
+ void deleteProduct(int id);
}
diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java
new file mode 100644
index 00000000..13912d65
--- /dev/null
+++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java
@@ -0,0 +1,64 @@
+package com.siriusxi.ms.store.api.core.product;
+
+
+import com.siriusxi.ms.store.api.core.product.dto.Product;
+import org.springframework.web.bind.annotation.*;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+/**
+ * Interface ProductEndpoint
is a higher level Interface
+ * to define Product Service endpoint APIs that follow ProductService
+ * interface. And to be implemented by service controllers.
+ *
+ * @see ProductService
+ *
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RequestMapping("products")
+public interface ProductEndpoint extends ProductService {
+
+ /**
+ * Sample usage:
+ *
+ *
curl $HOST:$PORT/products/1
curl -X POST $HOST:$PORT/products \ -H "Content-Type: application/json" --data \
+ * '{"productId":123,"name":"product 123","weight":123}'
curl -X DELETE $HOST:$PORT/products/1
curl -X POST $HOST:$PORT/products \ -H "Content-Type: application/json" --data \ - * '{"productId":123,"name":"product 123","weight":123}' + * Add product to the repository. * * @param body product to save. * @return just created product. + * @since v0.1 */ - @PostMapping( value = "products", - produces = APPLICATION_JSON_VALUE, - consumes = APPLICATION_JSON_VALUE) - Product createProduct(@RequestBody Product body); + Product createProduct(Product body); /** - * Sample usage: - * - *
curl -X DELETE $HOST:$PORT/products/1
+ * Delete the product from repository.
*
- * @param productId to be deleted.
+ * @implNote This method should be idempotent and always return 200 OK status.
+ * @param id to be deleted.
+ * @since v0.1
*/
- @DeleteMapping("products/{productId}")
- void deleteProduct(@PathVariable int productId);
+ void deleteProduct(int id);
}
diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/Product.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/dto/Product.java
similarity index 83%
rename from store-api/src/main/java/com/siriusxi/ms/store/api/core/product/Product.java
rename to store-api/src/main/java/com/siriusxi/ms/store/api/core/product/dto/Product.java
index 3bc9b4a2..1c5a3193 100644
--- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/Product.java
+++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/dto/Product.java
@@ -1,4 +1,4 @@
-package com.siriusxi.ms.store.api.core.product;
+package com.siriusxi.ms.store.api.core.product.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java
new file mode 100644
index 00000000..9cac81f1
--- /dev/null
+++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java
@@ -0,0 +1,59 @@
+package com.siriusxi.ms.store.api.core.recommendation;
+
+import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+/**
+ * Interface RecommendationEndpoint
is a higher level Interface to define
+ * Recommendation Service endpoint APIs, that follow RecommendationService
+ *
interface. And to be implemented by service controllers.
+ *
+ * @see RecommendationService
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RequestMapping("recommendations")
+public interface RecommendationEndpoint extends RecommendationService {
+
+ /**
+ * Sample usage:
+ *
+ *
curl $HOST:$PORT/recommendations?productId=1
curl -X POST $HOST:$PORT/recommendations \
+ * -H "Content-Type: application/json" --data \
+ * '{"productId":123,"recommendationId":456,"author":"me","rate":5,"content":"yada, yada, yada"
+ * }'
curl -X DELETE $HOST:$PORT/recommendations?productId=1
curl -X POST $HOST:$PORT/recommendations \ -H "Content-Type: application/json" --data \ - * '{"productId":123,"recommendationId":456,"author":"me","rate":5,"content":"yada, yada, yada"}' - * - * @param body the recommendation to add. - * @return currently created recommendation. - */ - @PostMapping(value = "recommendations", - produces = APPLICATION_JSON_VALUE, - consumes = APPLICATION_JSON_VALUE) - Recommendation createRecommendation(@RequestBody Recommendation body); - - /** - * Sample usage: - * - *
curl -X DELETE $HOST:$PORT/recommendations?productId=1
- *
- * @param productId to delete recommendations for.
- */
- @DeleteMapping(value = "recommendations")
- void deleteRecommendations(@RequestParam("productId") int productId);
+ /**
+ * Delete all product recommendations.
+ *
+ * @param productId to delete recommendations for.
+ * @since v0.1
+ */
+ void deleteRecommendations(int productId);
}
diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/Recommendation.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/dto/Recommendation.java
similarity index 85%
rename from store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/Recommendation.java
rename to store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/dto/Recommendation.java
index 5757c25c..d96eeff0 100644
--- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/Recommendation.java
+++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/dto/Recommendation.java
@@ -1,4 +1,4 @@
-package com.siriusxi.ms.store.api.core.recommendation;
+package com.siriusxi.ms.store.api.core.recommendation.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java
new file mode 100644
index 00000000..b544f838
--- /dev/null
+++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java
@@ -0,0 +1,65 @@
+package com.siriusxi.ms.store.api.core.review;
+
+import com.siriusxi.ms.store.api.core.review.dto.Review;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+/**
+ * Interface ReviewEndpoint
is a higher level Interface to define
+ * Review Service endpoint APIs, that follow ReviewService
interface.
+ * And to be implemented by service controllers.
+ *
+ * @see ReviewService
+ * @author mohamed.taman
+ * @version v1.0
+ * @since v3.0 codename Storm
+ */
+@RequestMapping("reviews")
+public interface ReviewEndpoint extends ReviewService{
+
+ /**
+ * Sample usage:
+ *
+ *
curl -X POST $HOST:$PORT/reviews \
+ * -H "Content-Type: application/json" --data \
+ * '{"productId":123,"reviewId":456,"author":"me","subject":"yada, yada, yada",
+ * "content":"yada, yada, yada"}'
curl $HOST:$PORT/reviews?productId=1
curl -X DELETE $HOST:$PORT/review?productId=1