View on GitHub

SCRATCH PAD

No polish, just pulse

Complete Guide to GraphQL with Java (Spring Boot) – From Zero to Hero 🚀

GraphQL is a powerful alternative to REST APIs, providing flexible, efficient data fetching. In this guide, I will explain why each concept exists and how it works, assuming you know nothing about GraphQL.

By the end, you’ll be able to build a fully functional GraphQL API in Java Spring Boot with queries, mutations, subscriptions, and security.


1. What is GraphQL and Why Do We Need It?

Imagine you are building an app that fetches user data from an API. With a traditional REST API, you might have endpoints like:

The problems?

  1. Over-fetching – You get extra data that you don’t need.
  2. Under-fetching – You need multiple API calls to get related data.

How GraphQL Solves These Issues


2. GraphQL vs REST – Which is Better?

Feature GraphQL REST
Data Fetching Select specific fields Returns the full response
Number of Endpoints Single endpoint (/graphql) Multiple endpoints (/users, /posts)
Over-fetching ❌ No (only requested fields) ✅ Yes (extra data is returned)
Under-fetching ❌ No (fetch related data in one call) ✅ Yes (multiple requests needed)
API Evolution Schema-based (no versioning) Versioned (/v1/users, /v2/users)

3. Installing GraphQL in Java Spring Boot

Since GraphQL is just a query language, it needs to be implemented in a backend framework. We’ll use Spring Boot because it provides:

Step 1: Add Dependencies

We need the following dependencies in pom.xml:

<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-spring-boot-starter</artifactId>
    <version>11.1.0</version>
</dependency>

<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java-tools</artifactId>
    <version>5.2.4</version>
</dependency>

Now, we can start defining our GraphQL schema.


4. GraphQL Schema – The Heart of GraphQL

Unlike REST APIs, where endpoints define responses, GraphQL uses a schema to define:

Example Schema (schema.graphqls)

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

type Query {
    getUser(id: ID!): User
    getAllUsers: [User]
}

type Mutation {
    createUser(name: String!, email: String!): User
    deleteUser(id: ID!): Boolean
}

💡 Why do we need this schema?
This schema acts as a contract between the client and server, ensuring structured data exchange.


5. Implementing GraphQL API in Java Spring Boot

Step 1: Define the Entity

GraphQL will interact with a database, so let’s define an entity.

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

    // Constructors, Getters, and Setters
}

💡 Why do we need an entity?
Entities represent database tables. Each instance corresponds to a row.


Step 2: Create the Repository

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

💡 Why use a repository?
The repository allows us to interact with the database without writing SQL.


Step 3: Create the GraphQL Service

@Service
public class UserService {
    private final UserRepository userRepository;

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

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

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

    public User createUser(String name, String email) {
        User user = new User();
        user.setName(name);
        user.setEmail(email);
        return userRepository.save(user);
    }

    public boolean deleteUser(Long id) {
        if (userRepository.existsById(id)) {
            userRepository.deleteById(id);
            return true;
        }
        return false;
    }
}

💡 Why use a service layer?
The service layer separates business logic from the GraphQL resolvers.


Step 4: Implement GraphQL Query Resolver

@Component
public class UserQueryResolver implements GraphQLQueryResolver {
    private final UserService userService;

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

    public User getUser(Long id) {
        return userService.getUserById(id);
    }

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

💡 Why use resolvers?
Resolvers tell GraphQL how to fetch data.


Step 5: Implement GraphQL Mutation Resolver

@Component
public class UserMutationResolver implements GraphQLMutationResolver {
    private final UserService userService;

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

    public User createUser(String name, String email) {
        return userService.createUser(name, email);
    }

    public boolean deleteUser(Long id) {
        return userService.deleteUser(id);
    }
}

💡 Why separate queries and mutations?
This follows GraphQL’s best practices for clarity and maintainability.


6. Querying Data in GraphQL

Let’s test our API!

Fetching a Single User

GraphQL Query:

{
    getUser(id: 1) {
        name
        email
    }
}

💡 Why use queries?
Queries allow us to fetch data efficiently.


7. Mutations – Modifying Data

Creating a User

GraphQL Mutation:

mutation {
    createUser(name: "Alice", email: "alice@example.com") {
        id
        name
        email
    }
}

💡 Why use mutations?
Mutations allow clients to modify server-side data.


8. Subscriptions – Real-Time Updates

GraphQL supports real-time updates using subscriptions.

Example Subscription

type Subscription {
    userCreated: User
}

💡 Why use subscriptions?
Subscriptions push data updates instead of clients polling.


9. Securing GraphQL API

To prevent unauthorized access, we use Spring Security.

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
    }
}

💡 Why secure GraphQL APIs?
Since GraphQL has one endpoint, it needs role-based access control.


10. GraphQL Tools for Development


11. Error Handling in GraphQL

GraphQL provides structured error responses.

Handling Errors in Java

@ControllerAdvice
public class GraphQLExceptionHandler {
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<GraphQLError> handleException(RuntimeException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new GraphQLError(ex.getMessage()));
    }
}

Resources

Here are some valuable resources to help you deepen your understanding of GraphQL, especially in the context of Java and Spring Boot:

  1. Official GraphQL Documentation: Provides a comprehensive overview of GraphQL concepts, syntax, and best practices.
  2. Spring for GraphQL Documentation: Detailed guide on integrating GraphQL with Spring applications, including setup and configuration.
  3. GraphQL Java Documentation: Covers the GraphQL Java implementation, offering insights into its usage and features.
  4. Spring’s Official Guide on Building a GraphQL Service: A step-by-step tutorial on creating a GraphQL service using Spring Boot.
  5. “How to GraphQL” Fullstack Tutorial: An in-depth tutorial that covers GraphQL concepts and implementations across various stacks, including Java.
  6. Baeldung’s Guide to Spring GraphQL: An article that explains setting up a GraphQL server using Spring Boot, with practical examples.
  7. GraphQL Java Kickstart’s Spring Boot Tutorial: A concise tutorial on creating a GraphQL server with Spring Boot in a few minutes.
  8. YouTube Tutorial: Spring Boot and GraphQL Tutorial: A video tutorial that walks through building a GraphQL API using Spring Boot.
  9. YouTube Playlist: Spring Boot GraphQL Tutorial - Full Course: A comprehensive video series covering various aspects of integrating GraphQL with Spring Boot.
  10. Auth0’s Guide on Building a GraphQL API with Spring Boot: A step-by-step guide demonstrating how to build a secured GraphQL API with Spring Boot.