Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit 20ca7b9

Browse files
authored
Merge pull request #128 from ashu-walmart/request-scoped-dataloader
Thanks a lot @ashu-walmart!
2 parents 60f1812 + 15830ec commit 20ca7b9

File tree

10 files changed

+328
-0
lines changed

10 files changed

+328
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
4+
### IntelliJ IDEA ###
5+
.idea
6+
*.iws
7+
*.iml
8+
*.ipr
9+
.DS_Store
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.graphql-java.example</groupId>
8+
<artifactId>request-scoped-dataloader</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<parent>
12+
<groupId>org.springframework.boot</groupId>
13+
<artifactId>spring-boot-starter-parent</artifactId>
14+
<version>2.0.0.RELEASE</version>
15+
</parent>
16+
17+
<properties>
18+
<graphql.java.servlet.version>6.1.2</graphql.java.servlet.version>
19+
<graphql.spring.version>5.0.2</graphql.spring.version>
20+
<java.version>1.8</java.version>
21+
<graphql.tools.version>5.2.0</graphql.tools.version>
22+
<graphql.java.version>9.2</graphql.java.version>
23+
</properties>
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>org.springframework.boot</groupId>
28+
<artifactId>spring-boot-starter-web</artifactId>
29+
</dependency>
30+
<dependency>
31+
<groupId>com.graphql-java</groupId>
32+
<artifactId>graphql-spring-boot-starter</artifactId>
33+
<version>${graphql.spring.version}</version>
34+
<exclusions>
35+
<exclusion>
36+
<groupId>com.graphql-java</groupId>
37+
<artifactId>graphql-java-servlet</artifactId>
38+
</exclusion>
39+
</exclusions>
40+
</dependency>
41+
<dependency>
42+
<groupId>com.graphql-java</groupId>
43+
<artifactId>graphql-java-servlet</artifactId>
44+
<version>${graphql.java.servlet.version}</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>com.google.guava</groupId>
48+
<artifactId>guava</artifactId>
49+
<version>21.0</version>
50+
</dependency>
51+
<dependency>
52+
<groupId>com.graphql-java</groupId>
53+
<artifactId>graphiql-spring-boot-starter</artifactId>
54+
<version>${graphql.spring.version}</version>
55+
</dependency>
56+
<dependency>
57+
<groupId>com.graphql-java</groupId>
58+
<artifactId>graphql-java-tools</artifactId>
59+
<version>${graphql.tools.version}</version>
60+
<exclusions>
61+
<exclusion>
62+
<groupId>com.graphql-java</groupId>
63+
<artifactId>graphql-java</artifactId>
64+
</exclusion>
65+
</exclusions>
66+
</dependency>
67+
<dependency>
68+
<groupId>com.graphql-java</groupId>
69+
<artifactId>graphql-java</artifactId>
70+
<version>${graphql.java.version}</version>
71+
</dependency>
72+
<dependency>
73+
<groupId>org.springframework.boot</groupId>
74+
<artifactId>spring-boot-starter-test</artifactId>
75+
<scope>test</scope>
76+
</dependency>
77+
</dependencies>
78+
79+
<build>
80+
<plugins>
81+
<plugin>
82+
<groupId>org.apache.maven.plugins</groupId>
83+
<artifactId>maven-compiler-plugin</artifactId>
84+
<configuration>
85+
<source>1.8</source>
86+
<target>1.8</target>
87+
</configuration>
88+
</plugin>
89+
</plugins>
90+
</build>
91+
92+
</project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
6+
7+
@SpringBootApplication
8+
public class Application extends SpringBootServletInitializer {
9+
public static void main(String[] args) {
10+
SpringApplication.run(Application.class, args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import graphql.servlet.GraphQLContext;
4+
import graphql.servlet.GraphQLContextBuilder;
5+
import org.dataloader.DataLoader;
6+
import org.dataloader.DataLoaderRegistry;
7+
import org.springframework.stereotype.Component;
8+
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.websocket.server.HandshakeRequest;
11+
import java.util.concurrent.CompletableFuture;
12+
13+
@Component
14+
public class CustomGraphQLContextBuilder implements GraphQLContextBuilder {
15+
16+
private final CustomerRepository customerRepository;
17+
18+
public CustomGraphQLContextBuilder(CustomerRepository customerRepository) {
19+
this.customerRepository = customerRepository;
20+
}
21+
22+
@Override
23+
public GraphQLContext build(HttpServletRequest req) {
24+
GraphQLContext context = new GraphQLContext(req);
25+
context.setDataLoaderRegistry(buildDataLoaderRegistry());
26+
27+
return context;
28+
}
29+
30+
@Override
31+
public GraphQLContext build() {
32+
GraphQLContext context = new GraphQLContext();
33+
context.setDataLoaderRegistry(buildDataLoaderRegistry());
34+
35+
return context;
36+
}
37+
38+
@Override
39+
public GraphQLContext build(HandshakeRequest request) {
40+
GraphQLContext context = new GraphQLContext(request);
41+
context.setDataLoaderRegistry(buildDataLoaderRegistry());
42+
43+
return context;
44+
}
45+
46+
private DataLoaderRegistry buildDataLoaderRegistry() {
47+
DataLoaderRegistry dataLoaderRegistry = new DataLoaderRegistry();
48+
dataLoaderRegistry.register("customerDataLoader",
49+
new DataLoader<Integer, String>(customerIds ->
50+
CompletableFuture.supplyAsync(() ->
51+
customerRepository.getUserNamesForIds(customerIds))));
52+
return dataLoaderRegistry;
53+
}
54+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
public class Customer {
4+
private int customerId;
5+
6+
public Customer(int customerId) {
7+
this.customerId = customerId;
8+
}
9+
10+
public int getCustomerId() {
11+
return customerId;
12+
}
13+
14+
public void setCustomerId(int customerId) {
15+
this.customerId = customerId;
16+
}
17+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import org.springframework.stereotype.Component;
4+
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.stream.Collectors;
9+
10+
@Component
11+
public class CustomerRepository {
12+
13+
private final Map<Integer, String> data;
14+
15+
private CustomerRepository() {
16+
data = new HashMap<Integer, String>();
17+
data.put(Integer.valueOf(101), "Customer Name 1");
18+
data.put(Integer.valueOf(102), "Customer Name 2");
19+
data.put(Integer.valueOf(103), "Customer Name 3");
20+
data.put(Integer.valueOf(104), "Customer Name 4");
21+
data.put(Integer.valueOf(105), "Customer Name 5");
22+
data.put(Integer.valueOf(106), "Customer Name 6");
23+
}
24+
25+
public List getUserNamesForIds(List<Integer> customerIds) {
26+
return customerIds.parallelStream().map(data::get).collect(Collectors.toList());
27+
}
28+
29+
public void updateUsernameForId(Integer customerId, String newName) {
30+
data.put(customerId, newName);
31+
}
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import com.coxautodev.graphql.tools.GraphQLResolver;
4+
import graphql.schema.DataFetchingEnvironment;
5+
import graphql.servlet.GraphQLContext;
6+
import org.dataloader.DataLoader;
7+
import org.springframework.stereotype.Component;
8+
9+
import java.util.concurrent.CompletableFuture;
10+
11+
@Component
12+
public class CustomerResolver implements GraphQLResolver<Customer> {
13+
14+
public CompletableFuture<String> getName(Customer customer, DataFetchingEnvironment dfe) {
15+
final DataLoader<Integer, String> dataloader = ((GraphQLContext) dfe.getContext())
16+
.getDataLoaderRegistry().get()
17+
.getDataLoader("customerDataLoader");
18+
19+
return dataloader.load(customer.getCustomerId());
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
4+
import org.springframework.stereotype.Component;
5+
6+
import java.util.Arrays;
7+
import java.util.HashMap;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.stream.Collectors;
11+
12+
@Component
13+
public class WalmartQueryResolver implements GraphQLQueryResolver {
14+
15+
private final Map<Integer, List<Integer>> walmartData;
16+
17+
public WalmartQueryResolver() {
18+
walmartData = new HashMap<>();
19+
walmartData.put(4177, Arrays.asList(101,102,103,104));
20+
}
21+
22+
public List<Customer> walmartCustomers(int storeNumber) {
23+
return walmartData.get(storeNumber).parallelStream().map(Customer::new).collect(Collectors.toList());
24+
}
25+
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
type Customer {
2+
customerId: Int!
3+
name: String!
4+
}
5+
6+
type Query {
7+
walmartCustomers(storeNumber: Int): [Customer]
8+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package graphql.servlet.examples.dataloader.requestscope;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.boot.test.web.client.TestRestTemplate;
9+
import org.springframework.http.HttpEntity;
10+
import org.springframework.http.HttpHeaders;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.test.context.junit4.SpringRunner;
13+
14+
import static org.junit.Assert.assertEquals;
15+
import static org.junit.Assert.assertNotEquals;
16+
17+
@RunWith(SpringRunner.class)
18+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
19+
public class ApplicationTest {
20+
21+
@Autowired
22+
private TestRestTemplate restTemplate;
23+
24+
@Autowired
25+
private CustomerRepository repository;
26+
27+
@Test
28+
public void testSanity() {
29+
this.restTemplate.getForObject("/graphql/schema.json", String.class);
30+
}
31+
32+
@Test
33+
public void testRequestScope() {
34+
35+
String requestGraphQL = "query {\n" +
36+
" walmartCustomers(storeNumber:4177){\n" +
37+
" customerId\n" +
38+
" name\n" +
39+
" }\n" +
40+
"}";
41+
HttpHeaders headers = new HttpHeaders();
42+
headers.add("content-type", "application/graphql");
43+
ResponseEntity<JsonNode> response = this.restTemplate.postForEntity("/graphql", new HttpEntity<>(requestGraphQL, headers), JsonNode.class);
44+
45+
assertEquals(response.getBody().toString(), "{\"data\":{\"walmartCustomers\":[{\"customerId\":101,\"name\":\"Customer Name 1\"},{\"customerId\":102,\"name\":\"Customer Name 2\"},{\"customerId\":103,\"name\":\"Customer Name 3\"},{\"customerId\":104,\"name\":\"Customer Name 4\"}]}}");
46+
47+
repository.updateUsernameForId(101, "New Name 1");
48+
49+
response = this.restTemplate.postForEntity("/graphql", new HttpEntity<>(requestGraphQL, headers), JsonNode.class);
50+
51+
assertEquals(response.getBody().toString(), "{\"data\":{\"walmartCustomers\":[{\"customerId\":101,\"name\":\"New Name 1\"},{\"customerId\":102,\"name\":\"Customer Name 2\"},{\"customerId\":103,\"name\":\"Customer Name 3\"},{\"customerId\":104,\"name\":\"Customer Name 4\"}]}}");
52+
;
53+
}
54+
55+
56+
}

0 commit comments

Comments
 (0)