From 81a722da64378c011b8706cecc199cc68eab071a Mon Sep 17 00:00:00 2001 From: heowc Date: Thu, 25 Feb 2021 20:27:50 +0900 Subject: [PATCH] Add graphQL --- SpringBootGraphQL/build.gradle | 13 +++ .../java/com/example/java/GraphQLConfig.java | 88 +++++++++++++++++++ .../com/example/java/GraphQLDataFetchers.java | 74 ++++++++++++++++ .../java/RuntimeWiringConfigurator.java | 10 +++ .../java/SpringBootGraphQLApplication.java | 13 +++ .../src/main/resources/application.properties | 0 .../src/main/resources/schema.graphqls | 17 ++++ .../SpringBootGraphQLApplicationTests.java | 13 +++ .../src/test/resources/graphql.http | 49 +++++++++++ settings.gradle | 3 + 10 files changed, 280 insertions(+) create mode 100644 SpringBootGraphQL/build.gradle create mode 100644 SpringBootGraphQL/src/main/java/com/example/java/GraphQLConfig.java create mode 100644 SpringBootGraphQL/src/main/java/com/example/java/GraphQLDataFetchers.java create mode 100644 SpringBootGraphQL/src/main/java/com/example/java/RuntimeWiringConfigurator.java create mode 100644 SpringBootGraphQL/src/main/java/com/example/java/SpringBootGraphQLApplication.java create mode 100644 SpringBootGraphQL/src/main/resources/application.properties create mode 100644 SpringBootGraphQL/src/main/resources/schema.graphqls create mode 100644 SpringBootGraphQL/src/test/java/com/example/java/SpringBootGraphQLApplicationTests.java create mode 100644 SpringBootGraphQL/src/test/resources/graphql.http diff --git a/SpringBootGraphQL/build.gradle b/SpringBootGraphQL/build.gradle new file mode 100644 index 00000000..c6ab56ed --- /dev/null +++ b/SpringBootGraphQL/build.gradle @@ -0,0 +1,13 @@ +group = 'com.example' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '1.8' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'com.graphql-java:graphql-java:16.0' + implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:2.0' + implementation 'org.springframework.boot:spring-boot-starter-web' +} diff --git a/SpringBootGraphQL/src/main/java/com/example/java/GraphQLConfig.java b/SpringBootGraphQL/src/main/java/com/example/java/GraphQLConfig.java new file mode 100644 index 00000000..d1ca011a --- /dev/null +++ b/SpringBootGraphQL/src/main/java/com/example/java/GraphQLConfig.java @@ -0,0 +1,88 @@ +package com.example.java; + +import graphql.GraphQL; +import graphql.schema.GraphQLSchema; +import graphql.schema.idl.RuntimeWiring; +import graphql.schema.idl.SchemaGenerator; +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ResourceUtils; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; + +@Configuration +class GraphQLConfig { + + @Autowired + private GraphQLDataFetchers graphQLDataFetchers; + @Autowired + private Optional> runtimeWiringConfigurerList; + + @Bean + GraphQL graphQL() throws Exception { + final String sdl = readAllLineToString(ResourceUtils.getURL("classpath:schema.graphqls").toURI()); + final GraphQLSchema schema = buildSchema(sdl); + return GraphQL.newGraphQL(schema).build(); + } + + private static String readAllLineToString(URI uri) { + try { + return Files.lines(Paths.get(uri), StandardCharsets.UTF_8) + .collect(Collectors.joining()); + } catch (IOException e) { + // ignored + e.printStackTrace(); + } + + return ""; + } + + private GraphQLSchema buildSchema(String sdl) { + final TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl); + final RuntimeWiring runtimeWiring = buildWiring(); + final SchemaGenerator schemaGenerator = new SchemaGenerator(); + return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); + } + + private RuntimeWiring buildWiring() { + final RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring(); + runtimeWiringConfigurerList.ifPresent(list -> list.forEach(it -> it.configure(builder))); + return builder.build(); + } + + @Bean + RuntimeWiringConfigurator bookById() { + return builder -> { + builder.type(newTypeWiring("Query") + .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher())); + }; + } + + @Bean + RuntimeWiringConfigurator book() { + return builder -> { + builder.type(newTypeWiring("Book") + .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())); + }; + } + + @Bean + RuntimeWiringConfigurator authorById() { + return builder -> { + builder.type(newTypeWiring("Query") + .dataFetcher("authorById", graphQLDataFetchers.getAuthorByIdDataFetcher())); + }; + } +} diff --git a/SpringBootGraphQL/src/main/java/com/example/java/GraphQLDataFetchers.java b/SpringBootGraphQL/src/main/java/com/example/java/GraphQLDataFetchers.java new file mode 100644 index 00000000..719b5c92 --- /dev/null +++ b/SpringBootGraphQL/src/main/java/com/example/java/GraphQLDataFetchers.java @@ -0,0 +1,74 @@ +package com.example.java; + +import graphql.com.google.common.collect.ImmutableMap; +import graphql.schema.DataFetcher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@Component +class GraphQLDataFetchers { + + private static final List> books = Arrays.asList( + ImmutableMap.of("id", "book-1", + "name", "Harry Potter and the Philosopher's Stone", + "pageCount", "223", + "authorId", "author-1"), + ImmutableMap.of("id", "book-2", + "name", "Moby Dick", + "pageCount", "635", + "authorId", "author-2"), + ImmutableMap.of("id", "book-3", + "name", "Interview with the vampire", + "pageCount", "371", + "authorId", "author-3") + ); + + private static final List> authors = Arrays.asList( + ImmutableMap.of("id", "author-1", + "firstName", "Joanne", + "lastName", "Rowling"), + ImmutableMap.of("id", "author-2", + "firstName", "Herman", + "lastName", "Melville"), + ImmutableMap.of("id", "author-3", + "firstName", "Anne", + "lastName", "Rice") + ); + + public DataFetcher> getBookByIdDataFetcher() { + return dataFetchingEnvironment -> { + String bookId = dataFetchingEnvironment.getArgument("id"); + return books + .stream() + .filter(book -> book.get("id").equals(bookId)) + .findFirst() + .orElse(null); + }; + } + + public DataFetcher> getAuthorDataFetcher() { + return dataFetchingEnvironment -> { + Map book = dataFetchingEnvironment.getSource(); + String authorId = book.get("authorId"); + return authors + .stream() + .filter(author -> author.get("id").equals(authorId)) + .findFirst() + .orElse(null); + }; + } + + public DataFetcher> getAuthorByIdDataFetcher() { + return dataFetchingEnvironment -> { + String authorId = dataFetchingEnvironment.getArgument("id"); + return authors + .stream() + .filter(author -> author.get("id").equals(authorId)) + .findFirst() + .orElse(null); + }; + } +} \ No newline at end of file diff --git a/SpringBootGraphQL/src/main/java/com/example/java/RuntimeWiringConfigurator.java b/SpringBootGraphQL/src/main/java/com/example/java/RuntimeWiringConfigurator.java new file mode 100644 index 00000000..97707ade --- /dev/null +++ b/SpringBootGraphQL/src/main/java/com/example/java/RuntimeWiringConfigurator.java @@ -0,0 +1,10 @@ + +package com.example.java; + +import graphql.schema.idl.RuntimeWiring; + +@FunctionalInterface +interface RuntimeWiringConfigurator { + + void configure(RuntimeWiring.Builder builder); +} \ No newline at end of file diff --git a/SpringBootGraphQL/src/main/java/com/example/java/SpringBootGraphQLApplication.java b/SpringBootGraphQL/src/main/java/com/example/java/SpringBootGraphQLApplication.java new file mode 100644 index 00000000..4f413f4e --- /dev/null +++ b/SpringBootGraphQL/src/main/java/com/example/java/SpringBootGraphQLApplication.java @@ -0,0 +1,13 @@ +package com.example.java; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootGraphQLApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootGraphQLApplication.class, args); + } +} + diff --git a/SpringBootGraphQL/src/main/resources/application.properties b/SpringBootGraphQL/src/main/resources/application.properties new file mode 100644 index 00000000..e69de29b diff --git a/SpringBootGraphQL/src/main/resources/schema.graphqls b/SpringBootGraphQL/src/main/resources/schema.graphqls new file mode 100644 index 00000000..0791e09d --- /dev/null +++ b/SpringBootGraphQL/src/main/resources/schema.graphqls @@ -0,0 +1,17 @@ +type Query { + bookById(id: ID): Book + authorById(id: ID): Author +} + +type Book { + id: ID + name: String + pageCount: Int + author: Author +} + +type Author { + id: ID + firstName: String + lastName: String +} \ No newline at end of file diff --git a/SpringBootGraphQL/src/test/java/com/example/java/SpringBootGraphQLApplicationTests.java b/SpringBootGraphQL/src/test/java/com/example/java/SpringBootGraphQLApplicationTests.java new file mode 100644 index 00000000..9a2e65a0 --- /dev/null +++ b/SpringBootGraphQL/src/test/java/com/example/java/SpringBootGraphQLApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.java; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringBootGraphQLApplicationTests { + + @Test + public void contextLoads() { + + } +} diff --git a/SpringBootGraphQL/src/test/resources/graphql.http b/SpringBootGraphQL/src/test/resources/graphql.http new file mode 100644 index 00000000..0e18ad97 --- /dev/null +++ b/SpringBootGraphQL/src/test/resources/graphql.http @@ -0,0 +1,49 @@ +POST http://localhost:8080/graphql +Content-Type: application/graphql + +{ + bookById(id: "book-1") { + id +}} + +### + +POST http://localhost:8080/graphql +Content-Type: application/graphql + +{ + bookById(id: "book-2") { + id + name + pageCount +}} + +### + +POST http://localhost:8080/graphql +Content-Type: application/graphql + +{ + bookById(id: "book-3") { + id + name + pageCount + author { + firstName + lastName + } +}} + +### + +POST http://localhost:8080/graphql +Content-Type: application/graphql + +{ + authorById(id: "author-1") { + id + firstName + lastName +}} + +### diff --git a/settings.gradle b/settings.gradle index 4b023a6b..baf1c50a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -39,6 +39,9 @@ findProject(':SpringBootException')?.name = 'spring-boot-exception' include 'SpringBootGracefulShutdown' findProject(':SpringBootGracefulShutdown')?.name = 'spring-boot-graceful-shutdown' +include 'SpringBootGraphQL' +findProject(':SpringBootGraphQL')?.name = 'spring-boot-graphql' + include 'SpringBootGRpc' findProject(':SpringBootGRpc')?.name = 'spring-boot-grpc'