diff --git a/graphql/graphql-java/pom.xml b/graphql/graphql-java/pom.xml
index 4e2444c1fb..f2733bf671 100644
--- a/graphql/graphql-java/pom.xml
+++ b/graphql/graphql-java/pom.xml
@@ -12,8 +12,24 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
+ ../../
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
+ false
+
+ central
+ Central Repository
+ https://repo.maven.apache.org/maven2
+
+
+
com.graphql-java
@@ -25,11 +41,114 @@
ratpack-core
${ratpack-core.version}
+
+ com.github.americanexpress.nodes
+ nodes
+ 0.5.0
+
+
+ com.graphql-java
+ graphql-java
+ 9.2
+
+
+ com.graphql-java
+ graphql-java-tools
+ 5.2.4
+
+
+ com.graphql-java
+ graphql-java-servlet
+ 6.1.3
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.0.1
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
+
+ org.mock-server
+ mockserver-netty
+ 5.11.2
+
+
+ org.mock-server
+ mockserver-client-java
+ 5.11.2
+
+
+ com.graphql-java-generator
+ graphql-java-runtime
+ ${graphql.java.generator.version}
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.8.2
+ test
+
+
+ org.assertj
+ assertj-core
+ 3.22.0
+ test
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ ${maven.compiler.target}
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ 10.0.7
+
+
+ maven-war-plugin
+ 3.1.0
+
+
+ com.graphql-java-generator
+ graphql-maven-plugin
+ ${graphql.java.generator.version}
+
+
+
+ generateClientCode
+
+
+
+
+ com.baeldung.graphql.generated
+ false
+ false
+ true
+
+
+
+
+
3.0.3
1.4.6
+ 3.1
+ 1.8
+ 1.8
+ 1.18
\ No newline at end of file
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/AmericanExpressNodes.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/AmericanExpressNodes.java
new file mode 100644
index 0000000000..446dbd416e
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/AmericanExpressNodes.java
@@ -0,0 +1,24 @@
+package com.baeldung.graphql.clients;
+
+import com.baeldung.graphql.data.Data;
+import io.aexp.nodes.graphql.GraphQLRequestEntity;
+import io.aexp.nodes.graphql.GraphQLResponseEntity;
+import io.aexp.nodes.graphql.GraphQLTemplate;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+
+public class AmericanExpressNodes {
+
+ public static GraphQLResponseEntity callGraphQLService(String url, String query) throws IOException {
+ GraphQLTemplate graphQLTemplate = new GraphQLTemplate();
+
+ GraphQLRequestEntity requestEntity = GraphQLRequestEntity.Builder()
+ .url(StringUtils.join(url, "?query=", query))
+ .request(Data.class)
+ .build();
+
+ return graphQLTemplate.query(requestEntity, Data.class);
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/ApacheHttpClient.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/ApacheHttpClient.java
new file mode 100644
index 0000000000..d4f88e62f5
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/clients/ApacheHttpClient.java
@@ -0,0 +1,25 @@
+package com.baeldung.graphql.clients;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class ApacheHttpClient {
+
+ public static HttpResponse callGraphQLService(String url, String query) throws URISyntaxException, IOException {
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet request = new HttpGet(url);
+ URI uri = new URIBuilder(request.getURI())
+ .addParameter("query", query)
+ .build();
+ request.setURI(uri);
+ return client.execute(request);
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Author.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Author.java
new file mode 100644
index 0000000000..876df27769
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Author.java
@@ -0,0 +1,31 @@
+package com.baeldung.graphql.data;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class Author {
+
+ private String name;
+ private String surname;
+
+ public Author() {
+
+ }
+
+ public Author(String name, String surname) {
+ this.name = name;
+ this.surname = surname;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public String getFullName() {
+ return StringUtils.join(getName(), " ", getSurname());
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Book.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Book.java
new file mode 100644
index 0000000000..6e6188368b
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Book.java
@@ -0,0 +1,25 @@
+package com.baeldung.graphql.data;
+
+public class Book {
+
+ private String title;
+ private Author author;
+
+ public Book() {
+
+ }
+
+ public Book(String title, Author author) {
+ this.title = title;
+ this.author = author;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public Author getAuthor() {
+ return author;
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/BookRepository.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/BookRepository.java
new file mode 100644
index 0000000000..f812ed088d
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/BookRepository.java
@@ -0,0 +1,19 @@
+package com.baeldung.graphql.data;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class BookRepository {
+
+ private static final List books = Stream.of(
+ new Book("Title 1", new Author("Pero", "Peric")),
+ new Book("Title 2", new Author("Marko", "Maric"))
+ ).collect(Collectors.toList());
+
+ public List getAllBooks() {
+ return Collections.unmodifiableList(books);
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Data.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Data.java
new file mode 100644
index 0000000000..63263a496b
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Data.java
@@ -0,0 +1,22 @@
+package com.baeldung.graphql.data;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Data {
+
+ private List allBooks;
+
+ public Data() {
+
+ }
+
+ public Data(List allBooks) {
+ this.allBooks = allBooks;
+ }
+
+ public List getAllBooks() {
+ return Collections.unmodifiableList(allBooks);
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Response.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Response.java
new file mode 100644
index 0000000000..eedd13e04e
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/data/Response.java
@@ -0,0 +1,19 @@
+package com.baeldung.graphql.data;
+
+public class Response {
+
+ private Data data;
+
+ public Response() {
+
+ }
+
+ public Response(Data data) {
+ this.data = data;
+ }
+
+ public Data getData() {
+ return data;
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLEndpoint.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLEndpoint.java
new file mode 100644
index 0000000000..c69144c9f5
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLEndpoint.java
@@ -0,0 +1,36 @@
+package com.baeldung.graphql.server;
+
+import com.baeldung.graphql.data.BookRepository;
+import com.coxautodev.graphql.tools.SchemaParser;
+import graphql.schema.GraphQLSchema;
+import graphql.servlet.SimpleGraphQLHttpServlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@WebServlet(urlPatterns = "/graphql")
+public class GraphQLEndpoint extends HttpServlet {
+
+ private SimpleGraphQLHttpServlet graphQLServlet;
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ graphQLServlet.service(req, resp);
+ }
+
+ @Override
+ public void init() {
+ GraphQLSchema schema = SchemaParser.newParser()
+ .resolvers(new GraphQLQuery(new BookRepository()))
+ .file("schema.graphqls")
+ .build()
+ .makeExecutableSchema();
+ graphQLServlet = SimpleGraphQLHttpServlet
+ .newBuilder(schema)
+ .build();
+ }
+}
diff --git a/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLQuery.java b/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLQuery.java
new file mode 100644
index 0000000000..8ba9fa25c5
--- /dev/null
+++ b/graphql/graphql-java/src/main/java/com/baeldung/graphql/server/GraphQLQuery.java
@@ -0,0 +1,21 @@
+package com.baeldung.graphql.server;
+
+import com.baeldung.graphql.data.Book;
+import com.baeldung.graphql.data.BookRepository;
+import com.coxautodev.graphql.tools.GraphQLQueryResolver;
+
+import java.util.List;
+
+public class GraphQLQuery implements GraphQLQueryResolver {
+
+ private final BookRepository repository;
+
+ public GraphQLQuery(BookRepository repository) {
+ this.repository = repository;
+ }
+
+ public List allBooks() {
+ return repository.getAllBooks();
+ }
+
+}
diff --git a/graphql/graphql-java/src/main/resources/schema.graphqls b/graphql/graphql-java/src/main/resources/schema.graphqls
new file mode 100644
index 0000000000..b0834e04b7
--- /dev/null
+++ b/graphql/graphql-java/src/main/resources/schema.graphqls
@@ -0,0 +1,17 @@
+type Book {
+ title: String!
+ author: Author
+}
+
+type Author {
+ name: String!
+ surname: String!
+}
+
+type Query {
+ allBooks: [Book]
+}
+
+schema {
+ query: Query
+}
\ No newline at end of file
diff --git a/graphql/graphql-java/src/test/java/com/baeldung/graphql/GraphQLMockServer.java b/graphql/graphql-java/src/test/java/com/baeldung/graphql/GraphQLMockServer.java
new file mode 100644
index 0000000000..fb5a789428
--- /dev/null
+++ b/graphql/graphql-java/src/test/java/com/baeldung/graphql/GraphQLMockServer.java
@@ -0,0 +1,85 @@
+package com.baeldung.graphql;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.mockserver.client.MockServerClient;
+import org.mockserver.integration.ClientAndServer;
+import org.mockserver.model.HttpStatusCode;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.URISyntaxException;
+
+import static org.mockserver.integration.ClientAndServer.startClientAndServer;
+import static org.mockserver.matchers.Times.exactly;
+import static org.mockserver.model.HttpRequest.request;
+import static org.mockserver.model.HttpResponse.response;
+
+public class GraphQLMockServer {
+
+ public static ClientAndServer mockServer;
+ public static String serviceUrl;
+
+ private static int serverPort;
+
+ public static final String SERVER_ADDRESS = "127.0.0.1";
+ public static final String HTTP_GET_POST = "GET";
+ public static final String PATH = "/graphql";
+
+ @BeforeAll
+ static void startServer() throws IOException, URISyntaxException {
+ serverPort = getFreePort();
+ serviceUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH;
+ mockServer = startClientAndServer(serverPort);
+ mockAllBooksTitleRequest();
+ mockAllBooksTitleAuthorRequest();
+ }
+
+ @AfterAll
+ static void stopServer() {
+ mockServer.stop();
+ }
+
+ private static void mockAllBooksTitleAuthorRequest() {
+ String requestQuery = "{allBooks{title,author{name,surname}}}";
+ String responseJson = "{\"data\":{\"allBooks\":[{\"title\":\"Title 1\",\"author\":{\"name\":\"Pero\",\"surname\":\"Peric\"}},{\"title\":\"Title 2\",\"author\":{\"name\":\"Marko\",\"surname\":\"Maric\"}}]}}";
+
+ new MockServerClient(SERVER_ADDRESS, serverPort)
+ .when(
+ request()
+ .withPath(PATH)
+ .withQueryStringParameter("query", requestQuery),
+ exactly(1)
+ )
+ .respond(
+ response()
+ .withStatusCode(HttpStatusCode.OK_200.code())
+ .withBody(responseJson)
+ );
+ }
+
+ private static void mockAllBooksTitleRequest() {
+ String requestQuery = "{allBooks{title}}";
+ String responseJson = "{\"data\":{\"allBooks\":[{\"title\":\"Title 1\"},{\"title\":\"Title 2\"}]}}";
+
+ new MockServerClient(SERVER_ADDRESS, serverPort)
+ .when(
+ request()
+ .withPath(PATH)
+ .withQueryStringParameter("query", requestQuery),
+ exactly(1)
+ )
+ .respond(
+ response()
+ .withStatusCode(HttpStatusCode.OK_200.code())
+ .withBody(responseJson)
+ );
+ }
+
+ private static int getFreePort () throws IOException {
+ try (ServerSocket serverSocket = new ServerSocket(0)) {
+ return serverSocket.getLocalPort();
+ }
+ }
+
+}
diff --git a/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/AmericanExpressNodesUnitTest.java b/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/AmericanExpressNodesUnitTest.java
new file mode 100644
index 0000000000..8466cdee76
--- /dev/null
+++ b/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/AmericanExpressNodesUnitTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.graphql.clients;
+
+import com.baeldung.graphql.GraphQLMockServer;
+import com.baeldung.graphql.data.Data;
+import io.aexp.nodes.graphql.GraphQLResponseEntity;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+class AmericanExpressNodesUnitTest extends GraphQLMockServer {
+
+ @Test
+ void givenGraphQLEndpoint_whenRequestingAllBooksWithTitle_thenExpectedJsonIsReturned() throws IOException {
+ GraphQLResponseEntity responseEntity = AmericanExpressNodes.callGraphQLService(serviceUrl, "{allBooks{title}}");
+
+ assertAll(
+ () -> assertThat(responseEntity.getResponse().getAllBooks()).hasSize(2),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(0).getTitle()).isEqualTo("Title 1"),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(1).getTitle()).isEqualTo("Title 2")
+ );
+ }
+
+ @Test
+ void givenGraphQLEndpoint_whenRequestingAllBooksWithTitleAndAuthor_thenExpectedJsonIsReturned() throws IOException {
+ GraphQLResponseEntity responseEntity = AmericanExpressNodes.callGraphQLService(serviceUrl, "{allBooks{title,author{name,surname}}}");
+
+ assertAll(
+ () -> assertThat(responseEntity.getResponse().getAllBooks()).hasSize(2),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(0).getTitle()).isEqualTo("Title 1"),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(0).getAuthor().getFullName()).isEqualTo("Pero Peric"),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(1).getTitle()).isEqualTo("Title 2"),
+ () -> assertThat(responseEntity.getResponse().getAllBooks().get(1).getAuthor().getFullName()).isEqualTo("Marko Maric")
+ );
+ }
+
+}
diff --git a/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/ApacheHttpClientUnitTest.java b/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/ApacheHttpClientUnitTest.java
new file mode 100644
index 0000000000..17d97e0d14
--- /dev/null
+++ b/graphql/graphql-java/src/test/java/com/baeldung/graphql/clients/ApacheHttpClientUnitTest.java
@@ -0,0 +1,49 @@
+package com.baeldung.graphql.clients;
+
+import com.baeldung.graphql.GraphQLMockServer;
+import com.baeldung.graphql.data.Response;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+class ApacheHttpClientUnitTest extends GraphQLMockServer {
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ @Test
+ void givenGraphQLEndpoint_whenRequestingAllBooksWithTitle_thenExpectedJsonIsReturned() throws IOException, URISyntaxException {
+ HttpResponse httpResponse = ApacheHttpClient.callGraphQLService(serviceUrl, "{allBooks{title}}");
+ String actualResponse = IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8.name());
+ Response parsedResponse = objectMapper.readValue(actualResponse, Response.class);
+
+ assertAll(
+ () -> assertThat(parsedResponse.getData().getAllBooks()).hasSize(2),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(0).getTitle()).isEqualTo("Title 1"),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(1).getTitle()).isEqualTo("Title 2")
+ );
+ }
+
+ @Test
+ void givenGraphQLEndpoint_whenRequestingAllBooksWithTitleAndAuthor_thenExpectedJsonIsReturned() throws IOException, URISyntaxException {
+ HttpResponse httpResponse = ApacheHttpClient.callGraphQLService(serviceUrl, "{allBooks{title,author{name,surname}}}");
+ String actualResponse = IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8.name());
+ Response parsedResponse = objectMapper.readValue(actualResponse, Response.class);
+
+ assertAll(
+ () -> assertThat(parsedResponse.getData().getAllBooks()).hasSize(2),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(0).getTitle()).isEqualTo("Title 1"),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(0).getAuthor().getFullName()).isEqualTo("Pero Peric"),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(1).getTitle()).isEqualTo("Title 2"),
+ () -> assertThat(parsedResponse.getData().getAllBooks().get(1).getAuthor().getFullName()).isEqualTo("Marko Maric")
+ );
+ }
+
+}