Open In App

How to Integrate and Call a GraphQL API in a Java Spring Boot Application?

Last Updated : 01 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

GraphQL is a more flexible query language and runtime for APIs that lets clients request exactly the data they need by making data fetching more efficient. Compared to REST, GraphQL allows clients to define the exact structure of the response, making data retrieval smoother and more efficient. Integrating GraphQL with Java applications, especially in microservices, can boost data fetching speed and overall performance.

In this article, we will learn how to make a call to a GraphQL service from a Java application using Spring Boot and graphql-java.

Prerequisites:

  • Basic knowledge of Java and Spring Boot.
  • Basic knowledge of the GraphQL.
  • Maven for building dependency management.
  • JDK and IntelliJ IDEA installed in your system.

Calling a GraphQL Service From a Java Application

To call a GraphQL service, it is necessary to understand the following concepts:

  • What is GraphQL?
  • Differences between GraphQL and REST
  • Using WebClient for GraphQL API interaction

GraphQL

GraphQL is an API query language that allows clients to specify exactly which data they need. Compared to REST, it is more efficient, as it supports:

  • Client-Specified Queries: The client defines the response structure, avoiding over-fetching and under-fetching of data.
  • Single Endpoint: Unlike REST, GraphQL uses one endpoint to handle all queries, mutations, and subscriptions.
  • Queries and Mutations:
    • Queries are used for data retrieval (similar to GET requests).
    • Mutations modify server data (similar to POST, PUT, or DELETE requests).
  • GraphQL Schema: Defines the data types and relationships available through the API, serving as a contract between server and client.

Setting Up the Java Application to Call GraphQL

To call a GraphQL service from Java, the main steps are defining the query, sending it to the GraphQL endpoint, and processing the response.

1. Define the GraphQL Query

GraphQL queries are JSON objects with a "query" key. For example:

{
"query": "query { users { id name email } }"
}

In this query, we request each user's id, name, and email.

2. Use WebClient to Send the Query

WebClient is a non-blocking HTTP client from Spring WebFlux. It is an alternative to RestTemplate, providing better performance and flexibility for modern web applications.

Why Use WebClient?

  • Non-blocking: Allows better handling of asynchronous operations.
  • Reactivity: Supports reactive programming, useful for handling data streams.

Constructing the WebClient: Configure WebClient with the GraphQL server’s base URL:

WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:8080/graphql")
.build();


Sending the Query: Send the query as a POST request using WebClient:

String query = "{ \"query\": \"query { users { id name email } }\" }";

String response = webClient.post()
.bodyValue(query)
.retrieve()
.bodyToMono(String.class)
.block();

This POST request sends the GraphQL query to the server, which returns the JSON response with the requested data.

3. Process the GraphQL Response

The GraphQL response is a JSON object containing the data key with the results. For instance:

{
"data": {
"users": [
{
"id": "1",
"name": "John Doe",
"email": "[email protected]"
},
{
"id": "2",
"name": "Jane Smith",
"email": "[email protected]"
}
]
}
}

This response includes the data object which contains the array of users.

By understanding these steps and the role of the each component, we can effectively integrate the GraphQL service with a Java application.

Example: Setting Up a GraphQL Server Application with Spring Boot

This section provides a sample setup for a GraphQL server with Spring Boot.

Step 1: Create a Spring Boot Project

Create a new Spring Boot project with the following settings:

  • Name: graphql-server-demo
  • Type: Maven Project

Click on the Next button.

Project Metadata

Step 2: Add the Dependencies

Add the following dependencies into the Spring Boot Project:

  • Spring Web
  • Spring Boot DevTools
  • Lombok
  • Spring Data JPA
  • MySQL Driver
  • Spring for GraphQL

Click on the Create button.

Add Dependencies

Project Structure

After the project creation done, set up the project structure as shown in the below image:

Project Folder Structure

Step 3: Configure Application Properties

Open the application.properties file and add the following MySQL, Hibernate and GraphQL configuration.

spring.application.name=graphql-server-demo
# MySQL Database configuration
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=mypassword
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

# Show SQL queries in the console (Optional)
spring.jpa.show-sql=true

# GraphQL Configuration
graphql.servlet.mapping=/graphql
graphql.graphiql.enabled=true

Step 4: Define the GraphQL Schema

Define a GraphQL schema for queries in schema.graphqls:

type Query {
users: [User]
userById(id: ID!): User
}

type User {
id: ID!
name: String!
email: String!
}

Step 5: Create the data.sql file

We will now create the data.sql file to insert the default data into the database.

INSERT INTO user (name, email) VALUES ('John Doe', '[email protected]');
INSERT INTO user (name, email) VALUES ('Jane Smith', '[email protected]');
INSERT INTO user (name, email) VALUES ('Alice Johnson', '[email protected]');
INSERT INTO user (name, email) VALUES ('Bob Brown', '[email protected]');
INSERT INTO user (name, email) VALUES ('Charlie Davis', '[email protected]');

Step 6: Create the User Entity

Create a User class to represent user data:

Java
package com.gfg.graphqlserverdemo;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;

@Data
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
}

Step 7: Create the UserRepository Interface

Java
package com.gfg.graphqlserverdemo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

Step 8: Create the UserService Class

Java
package com.gfg.graphqlserverdemo;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }
}

Step 9: Create the UserController Class

Java
package com.gfg.graphqlserverdemo;

import com.gfg.graphqlserverdemo.User;
import com.gfg.graphqlserverdemo.UserService;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Mono;

import java.util.List;

@Controller
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @QueryMapping
    public Mono<List<User>> users() {
        return (Mono<List<User>>) userService.getAllUsers();
    }

    @QueryMapping
    public Mono<User> userById(Long id) {
        return Mono.justOrEmpty(userService.getUserById(id));
    }
}

Step 10: Main class

No changes are required in the main class.

Java
package com.gfg.graphqlserverdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GraphqlServerDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(GraphqlServerDemoApplication.class, args);
    }
}

pom.xml File:

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>graphql-server-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>graphql-server-demo</name>
    <description>graphql-server-demo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-graphql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>11.1.0</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.graphql</groupId>
            <artifactId>spring-graphql-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Step 11: Run the Application

Once the project is completed, we will run the application and it will start at port 8080.

Server Application Running

Setting Up a GraphQL Client Application

Step 1: Create a new Spring Boot Project

Create a new Spring Boot project using IntelliJ IDEA, then choose the following options:

  • Name: graphql-client-demo
  • Language: Java
  • Type: Maven
  • Packaging: Jar

Click on the Next button.

Client Application Metadata

Step 2: Add the Dependencies

Add the following dependencies into the Spring Boot project:

  • Spring Reactive Web
  • Lombok
  • Spring Boot DevTools

Click on the Create button.

Add Dependencies

Project Structure

Once the project is created, set the file structure as shown in the below image:

Folder Structure

Step 3: Configure Application Properties

Now, we will configure the properties in application.properties.

spring.application.name=graphql-client-demo
server.port=8081
graphql.service.url=http://localhost:8080/graphql

Step 4: Create the User Class

Java
package com.gfg.graphqlclientdemo;

import lombok.Data;

@Data
public class User {
    private String id;
    private String name;
    private String email;
}

Step 5: Create the UserService Class

Java
package com.gfg.graphqlclientdemo;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.List;

@Service
public class UserService {

    private final WebClient webClient;
    private final ObjectMapper objectMapper;

    public UserService(@Value("${graphql.service.url}") String graphqlUrl) {
        this.webClient = WebClient.builder()
                .baseUrl(graphqlUrl)
                .build();
        this.objectMapper = new ObjectMapper();
    }

    public Mono<List<User>> fetchUsers() {
        String query = "{ \"query\": \"query { users { id name email } } }\" }";

        return webClient.post()
                .bodyValue(query)
                .retrieve()
                .onStatus(HttpStatusCode::isError,
                        response -> Mono.error(new RuntimeException("Failed to fetch users: " + response.statusCode().value()))
                )
                .bodyToMono(String.class)
                .map(response -> {
                    try {
                        JsonNode jsonNode = objectMapper.readTree(response);
                        JsonNode usersNode = jsonNode.get("data").get("users");
                        return objectMapper.convertValue(usersNode,
                                objectMapper.getTypeFactory().constructCollectionType(List.class, User.class));
                    } catch (Exception e) {
                        throw new RuntimeException("Failed to parse GraphQL response", e);
                    }
                });
    }
}

Step 6: Create the UserController class

Java
package com.gfg.graphqlclientdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/users")
    public List<User> getUsers() {
        return (List<User>) userService.fetchUsers();
    }
}

Step 7: Main class

No changes are required in the main class.

Java
package com.gfg.graphqlclientdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GraphqlClientDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(GraphqlClientDemoApplication.class, args);
    }
}

pom.xml File:

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>graphql-client-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>graphql-client-demo</name>
    <description>graphql-client-demo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Step 9: Run the Application

Once the project is completed, we will run the project and it will start at port 8081.

Client Application Running

Conclusion

Integrating GraphQL with a Java application allows for the efficient data fetching and flexibility in the API communication. By using the WebClient in the Spring Boot Project, we can easily send the queries to the GraphQL service and parse the results into Java objects. This method is particularly useful for the microservices and applications that need to fetch nested or complex data structures.


Next Article

Similar Reads