├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── cart-service
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── vtsukur
│ │ └── graphql
│ │ └── demo
│ │ └── cart
│ │ ├── CartServiceApp.java
│ │ ├── conf
│ │ ├── RepositoriesConfiguration.java
│ │ └── RestClientsConfiguration.java
│ │ ├── deps
│ │ └── ProductServiceRestClient.java
│ │ ├── domain
│ │ ├── Cart.java
│ │ ├── CartRepository.java
│ │ ├── CartService.java
│ │ └── Item.java
│ │ └── web
│ │ ├── graphql
│ │ ├── GraphQLJavaConfig.java
│ │ └── spqr
│ │ │ ├── CartGraph.java
│ │ │ ├── GraphQLController.java
│ │ │ └── ProductGraph.java
│ │ └── http
│ │ ├── CartController.java
│ │ └── CartWithProductsProjection.java
│ └── resources
│ ├── application.properties
│ └── schema.graphqls
├── mvnw
├── mvnw.cmd
├── pom.xml
├── product-service-api
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── vtsukur
│ └── graphql
│ └── demo
│ └── product
│ └── api
│ ├── Product.java
│ └── Products.java
└── product-service
├── pom.xml
└── src
└── main
├── java
└── org
│ └── vtsukur
│ └── graphql
│ └── demo
│ └── product
│ ├── ProductServiceApp.java
│ ├── conf
│ └── RepositoryConfiguration.java
│ ├── domain
│ ├── Product.java
│ └── ProductRepository.java
│ └── web
│ └── ProductController.java
└── resources
├── META-INF
└── spring-devtools.properties
└── application.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | nbproject/private/
21 | build/
22 | nbbuild/
23 | dist/
24 | nbdist/
25 | .nb-gradle/
26 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtsukur/graphql-java-online-store/bd9eb4caf8d3595dcccf93a6844007139aefbf7c/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip
2 |
--------------------------------------------------------------------------------
/cart-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.vtsukur.graphql.demo
7 | cart-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 1.5.13.RELEASE
15 |
16 |
17 |
18 |
19 |
20 | org.vtsukur.graphql.demo
21 | product-service-api
22 | 0.0.1-SNAPSHOT
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-data-jpa
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-web
32 |
33 |
34 | org.apache.httpcomponents
35 | httpclient
36 | 4.5.5
37 |
38 |
39 |
40 | org.projectlombok
41 | lombok
42 | true
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-devtools
48 | runtime
49 |
50 |
51 | org.hsqldb
52 | hsqldb
53 | runtime
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-test
59 | test
60 |
61 |
62 |
63 | com.graphql-java
64 | graphql-spring-boot-starter
65 | 3.10.0
66 |
67 |
68 | com.graphql-java
69 | graphql-java
70 | 7.0
71 |
72 |
73 | com.graphql-java
74 | graphql-java-tools
75 | 4.3.0
76 |
77 |
78 |
79 | com.graphql-java
80 | graphiql-spring-boot-starter
81 | 3.10.0
82 |
83 |
84 |
85 | io.leangen.graphql
86 | spqr
87 | 0.9.6
88 |
89 |
90 |
91 |
92 |
93 |
94 | org.springframework.boot
95 | spring-boot-maven-plugin
96 |
97 |
98 |
99 |
100 |
101 | 1.8
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/CartServiceApp.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class CartServiceApp {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(CartServiceApp.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/conf/RepositoriesConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.conf;
2 |
3 | import org.springframework.boot.CommandLineRunner;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.vtsukur.graphql.demo.cart.deps.ProductServiceRestClient;
7 | import org.vtsukur.graphql.demo.cart.domain.Cart;
8 | import org.vtsukur.graphql.demo.cart.domain.CartRepository;
9 | import org.vtsukur.graphql.demo.product.api.Product;
10 |
11 | @Configuration
12 | public class RepositoriesConfiguration {
13 |
14 | @Bean
15 | public CommandLineRunner commandLineRunner(CartRepository cartRepository,
16 | ProductServiceRestClient productServiceRestClient) {
17 | return ($) -> insertInitialData(cartRepository, productServiceRestClient);
18 | }
19 |
20 | private static void insertInitialData(CartRepository cartRepository,
21 | ProductServiceRestClient productServiceRestClient) {
22 | Product product1 = productServiceRestClient.fetchProduct("59eb83c0040fa80b29938e3f");
23 | Product product2 = productServiceRestClient.fetchProduct("59eb83c0040fa80b29938e40");
24 | Product product3 = productServiceRestClient.fetchProduct("59eb88bd040fa8125aa9c400");
25 |
26 | Cart cart = new Cart();
27 | cart.addProduct(product1.getId(), product1.getPrice(), 1);
28 | cart.addProduct(product2.getId(), product2.getPrice(), 2);
29 | cart.addProduct(product3.getId(), product3.getPrice(), 1);
30 | cartRepository.save(cart);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/conf/RestClientsConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.conf;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
6 | import org.springframework.web.client.RestTemplate;
7 | import org.vtsukur.graphql.demo.cart.deps.ProductServiceRestClient;
8 |
9 | @Configuration
10 | public class RestClientsConfiguration {
11 |
12 | @Bean
13 | public RestTemplate restTemplate() {
14 | return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
15 | }
16 |
17 | @Bean
18 | public ProductServiceRestClient productServiceRestClient() {
19 | return new ProductServiceRestClient(restTemplate(), "http://localhost:9090");
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/deps/ProductServiceRestClient.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.deps;
2 |
3 | import org.springframework.web.client.RestTemplate;
4 | import org.vtsukur.graphql.demo.product.api.Product;
5 |
6 | import java.net.URI;
7 |
8 | public class ProductServiceRestClient {
9 |
10 | private final RestTemplate http;
11 |
12 | private final String baseUrl;
13 |
14 | public ProductServiceRestClient(RestTemplate http, String baseUrl) {
15 | this.http = http;
16 | this.baseUrl = baseUrl;
17 | }
18 |
19 | public Product fetchProduct(String productId) {
20 | return http.getForObject(productUrl(productId), Product.class);
21 | }
22 |
23 | public URI productUrl(String productId) {
24 | return URI.create(String.format("%s/products/%s", baseUrl, productId));
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/domain/Cart.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.domain;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.*;
6 | import java.math.BigDecimal;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | @Entity
11 | @Data
12 | public class Cart {
13 |
14 | @Id
15 | @GeneratedValue
16 | private Long id;
17 |
18 | @ElementCollection(fetch = FetchType.EAGER)
19 | private List- items = new ArrayList<>();
20 |
21 | public BigDecimal getSubTotal() {
22 | return getItems().stream()
23 | .map(Item::getTotal)
24 | .reduce(BigDecimal.ZERO, BigDecimal::add);
25 | }
26 |
27 | public void addProduct(String id, BigDecimal price, int quantity) {
28 | Item item = getItems().stream()
29 | .filter(p -> p.getProductId().equals(id))
30 | .findFirst()
31 | .orElseGet(() -> {
32 | Item newItem = new Item(id, 0, BigDecimal.ZERO);
33 | getItems().add(newItem);
34 | return newItem;
35 | });
36 | item.setQuantity(item.getQuantity() + quantity);
37 | item.setTotal(price.multiply(BigDecimal.valueOf(item.getQuantity())));
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/domain/CartRepository.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.domain;
2 |
3 | import org.springframework.data.repository.CrudRepository;
4 |
5 | public interface CartRepository extends CrudRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/domain/CartService.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.domain;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.stereotype.Component;
5 | import org.vtsukur.graphql.demo.cart.deps.ProductServiceRestClient;
6 | import org.vtsukur.graphql.demo.product.api.Product;
7 |
8 | @Component
9 | public class CartService {
10 |
11 | private final CartRepository cartRepository;
12 |
13 | private final ProductServiceRestClient productServiceRestClient;
14 |
15 | @Autowired
16 | public CartService(CartRepository cartRepository, ProductServiceRestClient productServiceRestClient) {
17 | this.cartRepository = cartRepository;
18 | this.productServiceRestClient = productServiceRestClient;
19 | }
20 |
21 | public Cart findCart(Long cartId) {
22 | return cartRepository.findOne(cartId);
23 | }
24 |
25 | public Cart addProductToCart(Long cartId, String productId, int quantity) {
26 | Cart cart = cartRepository.findOne(cartId);
27 | Product product = productServiceRestClient.fetchProduct(productId);
28 | cart.addProduct(product.getId(), product.getPrice(), quantity);
29 | return cartRepository.save(cart);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/domain/Item.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.domain;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import javax.persistence.Column;
8 | import javax.persistence.Embeddable;
9 | import java.math.BigDecimal;
10 |
11 | @Embeddable
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | public class Item {
16 |
17 | @Column(nullable = false)
18 | private String productId;
19 |
20 | @Column(nullable = false)
21 | private int quantity;
22 |
23 | @Column(nullable = false)
24 | private BigDecimal total;
25 |
26 | Item(String productId, BigDecimal productPrice, int quantity) {
27 | this.productId = productId;
28 | this.quantity = quantity;
29 | this.total = BigDecimal.valueOf(quantity).multiply(productPrice);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/graphql/GraphQLJavaConfig.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.graphql;
2 |
3 | import com.coxautodev.graphql.tools.GraphQLMutationResolver;
4 | import com.coxautodev.graphql.tools.GraphQLQueryResolver;
5 | import com.coxautodev.graphql.tools.GraphQLResolver;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.web.client.RestTemplate;
10 | import org.vtsukur.graphql.demo.cart.domain.Cart;
11 | import org.vtsukur.graphql.demo.cart.domain.Item;
12 | import org.vtsukur.graphql.demo.cart.domain.CartService;
13 | import org.vtsukur.graphql.demo.product.api.Product;
14 |
15 | import java.util.List;
16 |
17 | @Configuration
18 | public class GraphQLJavaConfig {
19 |
20 | private final CartService cartService;
21 |
22 | private final RestTemplate http;
23 |
24 | @Autowired
25 | public GraphQLJavaConfig(CartService cartService, RestTemplate http) {
26 | this.cartService = cartService;
27 | this.http = http;
28 | }
29 |
30 | @Bean
31 | public GraphQLQueryResolver query() {
32 | return new GraphQLQueryResolver() {
33 | public String hello() { return "Hello, Unicorns!"; }
34 | public Cart cart(Long id) { return cartService.findCart(id); }
35 | };
36 | }
37 |
38 | @Bean
39 | public GraphQLResolver
- cartItemResolver() {
40 | return new GraphQLResolver
- () {
41 | public Product product(Item item) {
42 | return http.getForObject("http://localhost:9090/products/{id}",
43 | Product.class,
44 | item.getProductId());
45 | }
46 | };
47 | }
48 |
49 | @Bean
50 | public GraphQLResolver productResolver() {
51 | return new GraphQLResolver() {
52 | public List images(Product product, int limit) {
53 | return product.getImages().subList(
54 | 0, limit > 0 ? limit : product.getImages().size());
55 | }
56 | };
57 | }
58 |
59 | @Bean
60 | public GraphQLMutationResolver mutations() {
61 | return new GraphQLMutationResolver() {
62 | public Cart addProductToCart(Long cartId, String productId, int quantity) {
63 | return cartService.addProductToCart(cartId, productId, quantity);
64 | }
65 | };
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/graphql/spqr/CartGraph.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.graphql.spqr;
2 |
3 | import io.leangen.graphql.annotations.GraphQLArgument;
4 | import io.leangen.graphql.annotations.GraphQLMutation;
5 | import io.leangen.graphql.annotations.GraphQLQuery;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 | import org.vtsukur.graphql.demo.cart.domain.Cart;
10 | import org.vtsukur.graphql.demo.cart.domain.CartService;
11 |
12 | @Component
13 | @Slf4j
14 | public class CartGraph {
15 |
16 | private final CartService cartService;
17 |
18 | @Autowired
19 | public CartGraph(CartService cartService) {
20 | this.cartService = cartService;
21 | }
22 |
23 | @GraphQLQuery(name = "cart")
24 | public Cart cart(@GraphQLArgument(name = "id") Long id) {
25 | log.info("fetching cart with id={}", id);
26 | return cartService.findCart(id);
27 | }
28 |
29 | @GraphQLMutation(name = "addProductToCart")
30 | public Cart addProductToCart(@GraphQLArgument(name = "cartId") Long cartId,
31 | @GraphQLArgument(name = "productId") String productId,
32 | @GraphQLArgument(name = "quantity", defaultValue = "1") int quantity) {
33 | log.info("adding {} product(s) with id={} to cart with id={}", quantity, productId, cartId);
34 | return cartService.addProductToCart(cartId, productId, quantity);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/graphql/spqr/GraphQLController.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.graphql.spqr;
2 |
3 | import graphql.ExecutionInput;
4 | import graphql.ExecutionResult;
5 | import graphql.GraphQL;
6 | import graphql.analysis.MaxQueryComplexityInstrumentation;
7 | import graphql.analysis.MaxQueryDepthInstrumentation;
8 | import graphql.execution.batched.BatchedExecutionStrategy;
9 | import graphql.execution.instrumentation.ChainedInstrumentation;
10 | import graphql.schema.GraphQLSchema;
11 | import io.leangen.graphql.GraphQLSchemaGenerator;
12 | import io.leangen.graphql.metadata.strategy.query.AnnotatedResolverBuilder;
13 | import io.leangen.graphql.metadata.strategy.query.BeanResolverBuilder;
14 | import io.leangen.graphql.metadata.strategy.query.PublicResolverBuilder;
15 | import io.leangen.graphql.metadata.strategy.value.jackson.JacksonValueMapperFactory;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.http.MediaType;
18 | import org.springframework.web.bind.annotation.PostMapping;
19 | import org.springframework.web.bind.annotation.RequestBody;
20 | import org.springframework.web.bind.annotation.ResponseBody;
21 | import org.springframework.web.bind.annotation.RestController;
22 |
23 | import java.util.Arrays;
24 | import java.util.Map;
25 |
26 | @RestController
27 | public class GraphQLController {
28 |
29 | private final GraphQL graphQL;
30 |
31 | @Autowired
32 | public GraphQLController(CartGraph cartGraph, ProductGraph productQuery) {
33 | GraphQLSchema schema = new GraphQLSchemaGenerator()
34 | .withResolverBuilders(
35 | new BeanResolverBuilder("org.vtsukur.graphql.demo.cart.domain"),
36 | // Resolve by annotations.
37 | new AnnotatedResolverBuilder(),
38 | // Resolve public methods inside root package.
39 | new PublicResolverBuilder("org.vtsukur.graphql.demo.cart.web.graphql.spqr"))
40 | .withOperationsFromSingleton(cartGraph)
41 | .withOperationsFromSingleton(productQuery)
42 | .withValueMapperFactory(new JacksonValueMapperFactory())
43 | .generate();
44 | graphQL = GraphQL.newGraphQL(schema)
45 | .queryExecutionStrategy(new BatchedExecutionStrategy())
46 | .instrumentation(new ChainedInstrumentation(Arrays.asList(
47 | new MaxQueryComplexityInstrumentation(200),
48 | new MaxQueryDepthInstrumentation(20)
49 | )))
50 | .build();
51 | }
52 |
53 | @PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
54 | @ResponseBody
55 | public ExecutionResult execute(@RequestBody Map request) {
56 | return graphQL.execute(ExecutionInput.newExecutionInput()
57 | .query((String) request.get("query"))
58 | .operationName((String) request.get("operationName"))
59 | .build());
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/graphql/spqr/ProductGraph.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.graphql.spqr;
2 |
3 | import graphql.execution.batched.Batched;
4 | import io.leangen.graphql.annotations.GraphQLArgument;
5 | import io.leangen.graphql.annotations.GraphQLContext;
6 | import io.leangen.graphql.annotations.GraphQLEnvironment;
7 | import io.leangen.graphql.annotations.GraphQLQuery;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.stereotype.Component;
11 | import org.springframework.web.client.RestTemplate;
12 | import org.vtsukur.graphql.demo.cart.domain.Item;
13 | import org.vtsukur.graphql.demo.product.api.Product;
14 | import org.vtsukur.graphql.demo.product.api.Products;
15 |
16 | import java.util.List;
17 | import java.util.Set;
18 |
19 | import static java.util.stream.Collectors.joining;
20 |
21 | @Component
22 | @Slf4j
23 | public class ProductGraph {
24 |
25 | private final RestTemplate http;
26 |
27 | @Autowired
28 | public ProductGraph(RestTemplate http) {
29 | this.http = http;
30 | }
31 |
32 | @GraphQLQuery(name = "product")
33 | @Batched
34 | public List products(@GraphQLContext List
- items,
35 | @GraphQLEnvironment Set subFields) {
36 | return http.getForObject(
37 | "http://localhost:9090/products?ids={id}",
38 | Products.class,
39 | items.stream().map(Item::getProductId).collect(joining(",")),
40 | String.join(",", subFields)
41 | ).getProducts();
42 | }
43 |
44 | @GraphQLQuery(name = "images")
45 | public List images(@GraphQLContext Product product,
46 | @GraphQLArgument(name = "limit", defaultValue = "0") int limit) {
47 | return product.getImages().subList(
48 | 0, limit > 0 ? limit : product.getImages().size());
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/http/CartController.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.http;
2 |
3 | import lombok.val;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.web.bind.annotation.*;
6 | import org.vtsukur.graphql.demo.cart.deps.ProductServiceRestClient;
7 | import org.vtsukur.graphql.demo.cart.domain.Cart;
8 | import org.vtsukur.graphql.demo.cart.domain.Item;
9 | import org.vtsukur.graphql.demo.cart.domain.CartService;
10 | import org.vtsukur.graphql.demo.product.api.Product;
11 |
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | @RestController
16 | public class CartController {
17 |
18 | private final CartService cartService;
19 |
20 | private final ProductServiceRestClient productServiceRestClient;
21 |
22 | @Autowired
23 | public CartController(CartService cartService, ProductServiceRestClient productServiceRestClient) {
24 | this.cartService = cartService;
25 | this.productServiceRestClient = productServiceRestClient;
26 | }
27 |
28 | @RequestMapping("/carts/{id}")
29 | @ResponseBody
30 | public Object get(@PathVariable Long id,
31 | @RequestParam(value = "projection", required = false) String projection) {
32 | val cart = cartService.findCart(id);
33 | if ("with-products".equals(projection)) {
34 | return getProjectionWithProducts(cart);
35 | }
36 | return cart;
37 | }
38 |
39 | private CartWithProductsProjection getProjectionWithProducts(Cart source) {
40 | val cart = new CartWithProductsProjection();
41 | cart.setId(source.getId());
42 | cart.setItems(toItemsWithProducts(source.getItems()));
43 | cart.setSubTotal(source.getSubTotal());
44 | return cart;
45 | }
46 |
47 | private List toItemsWithProducts(List
- source) {
48 | return source.stream().map(sourceItem -> {
49 | val item = new CartWithProductsProjection.Item();
50 | item.setProduct(toProductProjection(productServiceRestClient.fetchProduct(sourceItem.getProductId())));
51 | item.setQuantity(sourceItem.getQuantity());
52 | item.setTotal(sourceItem.getTotal());
53 | return item;
54 | }).collect(Collectors.toList());
55 | }
56 |
57 | private CartWithProductsProjection.Item.ProductProjection toProductProjection(Product source) {
58 | val product = new CartWithProductsProjection.Item.ProductProjection();
59 | product.setId(source.getId());
60 | product.setTitle(source.getTitle());
61 | product.setPrice(source.getPrice());
62 | product.setSku(source.getSku());
63 | product.setImage(source.getImages().get(0));
64 | return product;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/cart-service/src/main/java/org/vtsukur/graphql/demo/cart/web/http/CartWithProductsProjection.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.cart.web.http;
2 |
3 | import lombok.Data;
4 |
5 | import java.math.BigDecimal;
6 | import java.util.List;
7 |
8 | @Data
9 | public class CartWithProductsProjection {
10 |
11 | private Long id;
12 |
13 | private List
- items;
14 |
15 | private BigDecimal subTotal;
16 |
17 | @Data
18 | public static class Item {
19 |
20 | private ProductProjection product;
21 |
22 | private int quantity;
23 |
24 | private BigDecimal total;
25 |
26 | @Data
27 | public static class ProductProjection {
28 |
29 | private String id;
30 |
31 | private String title;
32 |
33 | private BigDecimal price;
34 |
35 | private String image;
36 |
37 | private String sku;
38 |
39 | }
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/cart-service/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | logging.pattern.console=%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
2 | logging.level.org.apache.http.wire=INFO
3 |
4 | graphql.servlet.enabled=false
5 |
--------------------------------------------------------------------------------
/cart-service/src/main/resources/schema.graphqls:
--------------------------------------------------------------------------------
1 | schema {
2 | query: EntryPoint
3 | mutation: Mutations
4 | }
5 |
6 | type EntryPoint {
7 | hello: String @deprecated(reason: "just playing around!")
8 | cart(id: ID!): Cart
9 | }
10 |
11 | type Cart {
12 | id: ID!
13 | items: [Item!]!
14 | subTotal: Float!
15 | }
16 |
17 | type Item {
18 | quantity: Int!
19 | product: Product!
20 | total: BigDecimal!
21 | }
22 |
23 | type Product {
24 | id: ID!
25 | title: String!
26 | price: BigDecimal!
27 | description: String
28 | sku: String!
29 | images(limit: Int = 0): [String!]!
30 | }
31 |
32 | type Mutations {
33 | addProductToCart(cartId: ID!, productId: ID!, quantity: Int = 0): Cart
34 | }
35 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.vtsukur.graphql.demo
7 | graphql-java-online-store
8 | 0.0.1-SNAPSHOT
9 | pom
10 |
11 | graphql-java-online-store
12 | Demo of Spring-based GraphQL server in Java
13 |
14 |
15 | cart-service
16 | product-service
17 | product-service-api
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/product-service-api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | product-service-api
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 |
11 | org.vtsukur.graphql.demo
12 | graphql-java-online-store
13 | 0.0.1-SNAPSHOT
14 |
15 |
16 |
17 |
18 | com.fasterxml.jackson.core
19 | jackson-annotations
20 | 2.8.0
21 |
22 |
23 |
24 | org.projectlombok
25 | lombok
26 | 1.16.20
27 | true
28 |
29 |
30 |
31 |
32 |
33 |
34 | org.apache.maven.plugins
35 | maven-compiler-plugin
36 | 3.7.0
37 |
38 | 1.8
39 | 1.8
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/product-service-api/src/main/java/org/vtsukur/graphql/demo/product/api/Product.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.api;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.Data;
5 |
6 | import java.math.BigDecimal;
7 | import java.util.List;
8 |
9 | @Data
10 | @JsonInclude(JsonInclude.Include.NON_NULL)
11 | public class Product {
12 |
13 | private String id;
14 |
15 | private String title;
16 |
17 | private BigDecimal price;
18 |
19 | private String description;
20 |
21 | private String sku;
22 |
23 | private List images;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/product-service-api/src/main/java/org/vtsukur/graphql/demo/product/api/Products.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.api;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.util.List;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class Products {
13 |
14 | private List products;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/product-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.vtsukur.graphql.demo
7 | product-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 1.5.13.RELEASE
15 |
16 |
17 |
18 |
19 |
20 | org.vtsukur.graphql.demo
21 | product-service-api
22 | 0.0.1-SNAPSHOT
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-data-mongodb
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-web
32 |
33 |
34 | de.flapdoodle.embed
35 | de.flapdoodle.embed.mongo
36 | 2.0.3
37 |
38 |
39 | cz.jirutka.spring
40 | embedmongo-spring
41 | 1.3.1
42 |
43 |
44 | net.sf.dozer
45 | dozer
46 | 5.5.1
47 |
48 |
49 |
50 | org.projectlombok
51 | lombok
52 | true
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-devtools
58 | runtime
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-test
64 | test
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-maven-plugin
73 |
74 |
75 |
76 |
77 |
78 | 1.8
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/product-service/src/main/java/org/vtsukur/graphql/demo/product/ProductServiceApp.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ProductServiceApp {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ProductServiceApp.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/product-service/src/main/java/org/vtsukur/graphql/demo/product/conf/RepositoryConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.conf;
2 |
3 | import cz.jirutka.spring.embedmongo.EmbeddedMongoFactoryBean;
4 | import org.springframework.boot.CommandLineRunner;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.data.mongodb.core.MongoTemplate;
8 | import org.vtsukur.graphql.demo.product.domain.Product;
9 | import org.vtsukur.graphql.demo.product.domain.ProductRepository;
10 |
11 | import java.io.IOException;
12 | import java.math.BigDecimal;
13 | import java.util.Arrays;
14 | import java.util.Collections;
15 |
16 | @Configuration
17 | public class RepositoryConfiguration {
18 |
19 | @Bean
20 | public CommandLineRunner commandLineRunner(ProductRepository productRepository) {
21 | return ($) -> insertInitialData(productRepository);
22 | }
23 |
24 | private static void insertInitialData(ProductRepository productRepository) {
25 | Product product1 = new Product(
26 | "59eb83c0040fa80b29938e3f",
27 | "Combo Pack with Dreamy Eyes 12\" (Pink) Soft Toy",
28 | BigDecimal.valueOf(26.99),
29 | "Spread Unicorn love amongst your friends and family by " +
30 | "purchasing a Unicorn adoption combo pack today. " +
31 | "You'll receive your very own fabulous adoption pack and a " +
32 | "12\" Dreamy Eyes (Pink) cuddly toy. It makes the perfect gift for loved ones. " +
33 | "Go on, you know you want to, adopt today!",
34 | "010",
35 | Arrays.asList(
36 | "http://localhost:8080/img/918d8d4cc83d4e5f8680ca4edfd5b6b2.jpg",
37 | "http://localhost:8080/img/f343889c0bb94965845e65d3f39f8798.jpg",
38 | "http://localhost:8080/img/dd55129473e04f489806db0dc6468dd9.jpg",
39 | "http://localhost:8080/img/64eba4524a1f4d5d9f1687a815795643.jpg",
40 | "http://localhost:8080/img/5727549e9131440dbb3cd707dce45d0f.jpg",
41 | "http://localhost:8080/img/28ae9369ec3c442dbfe6901434ad15af.jpg"
42 | )
43 | );
44 | productRepository.save(product1);
45 |
46 | Product product2 = new Product(
47 | "59eb83c0040fa80b29938e40",
48 | "Dreamy Eyes 12\" (Pink) Unicorn Soft Toy",
49 | BigDecimal.valueOf(12.99),
50 | "A fabulous 12\" pink and white Unicorn soft toy for you to snuggle at leisure. " +
51 | "Also makes the perfect gift for loved ones. Go on you know you want to, adopt today!",
52 | "006",
53 | Collections.singletonList("http://localhost:8080/img/f343889c0bb94965845e65d3f39f8798.jpg")
54 | );
55 | productRepository.save(product2);
56 |
57 | Product product3 = new Product(
58 | "59eb88bd040fa8125aa9c400",
59 | "Combo Pack with Dreamy Eyes 12\" (White) Soft Toy",
60 | BigDecimal.valueOf(26.99),
61 | "Spread Unicorn love amongst your friends and family by " +
62 | "purchasing a Unicorn adoption combo pack today. " +
63 | "You'll receive your very own fabulous adoption pack and a " +
64 | "12\" Dreamy Eyes (White) cuddly toy. It makes the perfect gift for loved ones. " +
65 | "Go on, you know you want to, adopt today!",
66 | "010",
67 | Arrays.asList(
68 | "http://localhost:8080/img/fb72e75c5f29488db41abf2f918769e4.jpg",
69 | "http://localhost:8080/img/cb8314b3b1e64e6998aad9ab426789be.jpg",
70 | "http://localhost:8080/img/dd55129473e04f489806db0dc6468dd9.jpg",
71 | "http://localhost:8080/img/64eba4524a1f4d5d9f1687a815795643.jpg",
72 | "http://localhost:8080/img/5727549e9131440dbb3cd707dce45d0f.jpg",
73 | "http://localhost:8080/img/28ae9369ec3c442dbfe6901434ad15af.jpg"
74 | )
75 | );
76 | productRepository.save(product3);
77 | }
78 |
79 | @Bean
80 | public MongoTemplate mongoTemplate() throws IOException {
81 | EmbeddedMongoFactoryBean mongoBean = new EmbeddedMongoFactoryBean();
82 | mongoBean.setBindIp("localhost");
83 | return new MongoTemplate(mongoBean.getObject(), "products_db");
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/product-service/src/main/java/org/vtsukur/graphql/demo/product/domain/Product.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.domain;
2 |
3 | import lombok.Data;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.data.annotation.PersistenceConstructor;
6 | import org.springframework.data.mongodb.core.mapping.Document;
7 |
8 | import java.math.BigDecimal;
9 | import java.util.List;
10 |
11 | @Data
12 | @RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor))
13 | @Document
14 | public class Product {
15 |
16 | private final String id;
17 |
18 | private final String title;
19 |
20 | private final BigDecimal price;
21 |
22 | private final String description;
23 |
24 | private final String sku;
25 |
26 | private final List images;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/product-service/src/main/java/org/vtsukur/graphql/demo/product/domain/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.domain;
2 |
3 | import org.springframework.data.repository.CrudRepository;
4 |
5 | import java.util.List;
6 |
7 | public interface ProductRepository extends CrudRepository {
8 |
9 | List findAllBy();
10 |
11 | List findAllByIdIn(String[] ids);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/product-service/src/main/java/org/vtsukur/graphql/demo/product/web/ProductController.java:
--------------------------------------------------------------------------------
1 | package org.vtsukur.graphql.demo.product.web;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 | import org.dozer.DozerBeanMapper;
5 | import org.dozer.loader.api.BeanMappingBuilder;
6 | import org.dozer.loader.api.TypeMappingOptions;
7 | import org.springframework.beans.BeanUtils;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.util.ReflectionUtils;
10 | import org.springframework.web.bind.annotation.*;
11 | import org.vtsukur.graphql.demo.product.domain.ProductRepository;
12 | import org.vtsukur.graphql.demo.product.api.Product;
13 | import org.vtsukur.graphql.demo.product.api.Products;
14 |
15 | import java.beans.PropertyDescriptor;
16 | import java.util.Arrays;
17 | import java.util.List;
18 | import java.util.function.Function;
19 |
20 | import static java.util.stream.Collectors.toList;
21 |
22 | @RestController
23 | @RequestMapping("products")
24 | public class ProductController {
25 |
26 | private final ProductRepository productRepository;
27 |
28 | private final DozerBeanMapper mapper = new DozerBeanMapper();
29 |
30 | @Autowired
31 | public ProductController(ProductRepository productRepository) {
32 | this.productRepository = productRepository;
33 | mapper.addMapping(new BeanMappingBuilder() {
34 | protected void configure() {
35 | mapping(org.vtsukur.graphql.demo.product.domain.Product.class, Product.class, TypeMappingOptions.oneWay());
36 | }
37 | });
38 | }
39 |
40 | @RequestMapping
41 | @ResponseBody
42 | public Products getProducts(@RequestParam(value = "ids", required = false) String rawIds,
43 | @RequestParam(value = "include", required = false) String rawFields) {
44 | List products = StringUtils.isBlank(rawIds) ?
45 | productRepository.findAllBy() :
46 | productRepository.findAllByIdIn(rawIds.split(","));
47 | Function mapper = StringUtils.isBlank(rawFields) ?
48 | this::toFullSingletonResource :
49 | new FieldMapper(rawFields.split(","));
50 | return new Products(toListResource(products, mapper));
51 | }
52 |
53 | @RequestMapping("/{id}")
54 | @ResponseBody
55 | public Product getProduct(@PathVariable("id") String id) {
56 | return toFullSingletonResource(productRepository.findOne(id));
57 | }
58 |
59 | private List toListResource(List products, Function mapper) {
60 | return products.stream().map(mapper).collect(toList());
61 | }
62 |
63 | private Product toFullSingletonResource(org.vtsukur.graphql.demo.product.domain.Product product) {
64 | return mapper.map(product, Product.class);
65 | }
66 |
67 | private static class FieldMapper implements Function {
68 |
69 | private final String[] fields;
70 |
71 | FieldMapper(String[] fields) {
72 | this.fields = fields;
73 | }
74 |
75 | @Override
76 | public Product apply(org.vtsukur.graphql.demo.product.domain.Product in) {
77 | Product out = new Product();
78 | Arrays.stream(fields).forEach(field -> {
79 | PropertyDescriptor sourceDescriptor = BeanUtils.getPropertyDescriptor(org.vtsukur.graphql.demo.product.domain.Product.class, field);
80 | Object value = ReflectionUtils.invokeMethod(sourceDescriptor.getReadMethod(), in);
81 |
82 | PropertyDescriptor destDescriptor = BeanUtils.getPropertyDescriptor(Product.class, field);
83 | ReflectionUtils.invokeMethod(destDescriptor.getWriteMethod(), out, value);
84 | });
85 | return out;
86 | }
87 |
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/product-service/src/main/resources/META-INF/spring-devtools.properties:
--------------------------------------------------------------------------------
1 | restart.include.dozer=/dozer-5.5.1.jar
2 |
--------------------------------------------------------------------------------
/product-service/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9090
2 |
--------------------------------------------------------------------------------