Skip to content

Commit a9392b4

Browse files
committed
Simple first version of graphql client
1 parent fb8abb6 commit a9392b4

File tree

15 files changed

+806
-13
lines changed

15 files changed

+806
-13
lines changed

gradle.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ PROJECT_DEV_NAME = Michiel Oliemans
1313

1414
LIB_PROJECT_REACTOR_VER = 1.0.1
1515

16+
### Test libraries
17+
18+
LIB_GRAPHQL_TOOLS_VER = 6.0.0
19+
LIB_GRAPHQL_SPRING_VER = 7.0.0
20+
1621
### Gradle Plugins
1722

1823
LIB_SPRING_BOOT_VER = 2.2.5.RELEASE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.ComponentScan;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.web.reactive.function.client.WebClient;
9+
10+
@Slf4j
11+
@Configuration
12+
@ComponentScan(basePackageClasses = GraphQLWebClientImpl.class)
13+
public class GraphQLWebClientAutoConfiguration {
14+
15+
@Bean
16+
@ConditionalOnMissingBean
17+
public WebClient webClient() {
18+
return null;
19+
}
20+
21+
@Bean
22+
@ConditionalOnMissingBean
23+
public GraphQLWebClient graphQLWebClient(WebClient webClient) {
24+
return new GraphQLWebClientImpl(webClient);
25+
}
26+
27+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2+
graphql.kickstart.spring.webclient.boot.GraphQLWebClientAutoConfiguration

graphql-webclient/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
dependencies {
22
compileOnly "org.springframework.boot:spring-boot-starter-webflux"
3+
4+
testImplementation "org.springframework.boot:spring-boot-starter-webflux"
5+
testImplementation "org.springframework.boot:spring-boot-starter-test"
6+
testImplementation "com.graphql-java-kickstart:graphql-kickstart-spring-boot-starter-webflux:$LIB_GRAPHQL_SPRING_VER"
7+
testImplementation "com.graphql-java-kickstart:graphql-kickstart-spring-boot-starter-tools:$LIB_GRAPHQL_SPRING_VER"
8+
testImplementation "com.graphql-java-kickstart:graphql-java-tools:$LIB_GRAPHQL_TOOLS_VER"
39
}

graphql-webclient/src/main/java/graphql/kickstart/spring/webclient/GraphQLWebClient.java

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import lombok.Builder;
4+
import lombok.Value;
5+
6+
@Value
7+
@Builder
8+
class GraphQLRequest {
9+
10+
String query;
11+
Object variables;
12+
String operationName;
13+
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Map.Entry;
6+
import lombok.Data;
7+
8+
@Data
9+
class GraphQLResponse {
10+
11+
private Map<String, Object> data;
12+
private List<String> errors;
13+
14+
<T> T getFirstObject(Class<T> type) {
15+
return (T) data.entrySet().stream().findFirst().map(Entry::getValue).orElseThrow();
16+
}
17+
18+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import java.util.Map;
4+
import reactor.core.publisher.Mono;
5+
6+
public interface GraphQLWebClient {
7+
8+
<T> Mono<T> query(String resource, Map<String, Object> variables, Class<T> returnType);
9+
10+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.nio.charset.StandardCharsets;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import lombok.RequiredArgsConstructor;
9+
import lombok.SneakyThrows;
10+
import lombok.extern.slf4j.Slf4j;
11+
import org.springframework.core.io.ClassPathResource;
12+
import org.springframework.core.io.Resource;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.util.StreamUtils;
15+
import org.springframework.web.reactive.function.client.WebClient;
16+
import reactor.core.publisher.Mono;
17+
18+
@Slf4j
19+
@RequiredArgsConstructor
20+
class GraphQLWebClientImpl implements GraphQLWebClient {
21+
22+
private final WebClient webClient;
23+
24+
@Override
25+
public <T> Mono<T> query(String resource, Map<String, Object> variables, Class<T> returnType) {
26+
GraphQLRequest request = GraphQLRequest.builder()
27+
.query(loadQuery(resource))
28+
.variables(variables)
29+
.build();
30+
31+
return webClient.post()
32+
.uri("/graphql")
33+
.contentType(MediaType.APPLICATION_JSON)
34+
.bodyValue(request)
35+
.retrieve()
36+
.bodyToMono(GraphQLResponse.class)
37+
.map(it -> it.getFirstObject(returnType));
38+
}
39+
40+
@SneakyThrows
41+
private String loadQuery(String path) {
42+
// Resource resource = resourceLoader.getResource("classpath:" + location);
43+
return loadResource(new ClassPathResource(path));
44+
}
45+
46+
private String loadResource(Resource resource) throws IOException {
47+
try (InputStream inputStream = resource.getInputStream()) {
48+
return StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
49+
}
50+
}
51+
52+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package graphql.kickstart.spring.webclient;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class TestApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(TestApplication.class, args);
11+
}
12+
13+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertNotNull;
5+
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
10+
import org.springframework.boot.web.server.LocalServerPort;
11+
import org.springframework.web.reactive.function.client.WebClient;
12+
import reactor.core.publisher.Mono;
13+
14+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
15+
class GraphQLWebClientTest {
16+
17+
@LocalServerPort
18+
private int randomServerPort;
19+
20+
private GraphQLWebClient graphqlClient;
21+
22+
@BeforeEach
23+
void beforeEach() {
24+
WebClient webClient = WebClient.builder()
25+
.baseUrl("http://localhost:" + randomServerPort)
26+
.build();
27+
graphqlClient = new GraphQLWebClientImpl(webClient);
28+
}
29+
30+
@Test
31+
void queryWithoutVariablesSucceeds() {
32+
Mono<String> response = graphqlClient.query("query-test.graphql", null, String.class);
33+
assertNotNull("response should not be null", response);
34+
assertEquals("response should equal 'test'", "test", response.block());
35+
}
36+
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package graphql.kickstart.spring.webclient.testapp;
2+
3+
import graphql.kickstart.tools.GraphQLQueryResolver;
4+
import org.springframework.stereotype.Component;
5+
6+
@Component
7+
class Query implements GraphQLQueryResolver {
8+
9+
String test() {
10+
return "test";
11+
}
12+
13+
String echo(String value) {
14+
return value;
15+
}
16+
17+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
query {
2+
test
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type Query {
2+
test: String!
3+
echo(value: String!): String!
4+
}

0 commit comments

Comments
 (0)