Quick Guide to Integrating GraphQL with Spring Boot

This tutorial shows how to quickly add GraphQL support to a Spring Boot web project by creating a Maven project, adding custom dependencies, defining schema files, implementing resolvers and a controller, and testing query and mutation endpoints, all without using the official graphql‑java‑tools starter.

Architecture Digest
Architecture Digest
Architecture Digest
Quick Guide to Integrating GraphQL with Spring Boot

This article demonstrates a fast way to add GraphQL support to a Spring Boot web project, avoiding the official graphql-java-tools starter and using a more flexible configuration.

Quick start – generate a Spring Boot project with Spring Initializr, replace application.properties with application.yml, and add the required Maven dependencies.

Required Maven dependencies (pom.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>2.4.6</version>
        <relativePath/>
    </parent>
    <groupId>com.xuxd</groupId>
    <artifactId>graphql.demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <lombok.version>1.18.20</lombok.version>
        <graphql-java-tools.version>11.0.1</graphql-java-tools.version>
        <gson.version>2.8.7</gson.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>${graphql-java-tools.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>${gson.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

After adding the dependencies, a GraphQLProvider component creates the GraphQL instance, loads schema files ( base.graphqls and item.graphqls) and registers query and mutation resolvers.

@Component
public class GraphQLProvider {
    private GraphQL graphQL;

    @Autowired
    private IItemService itemService;

    @Bean
    public GraphQL graphQL() {
        return graphQL;
    }

    @PostConstruct
    public void init() throws IOException {
        GraphQLSchema graphQLSchema = SchemaParser.newParser()
            .file("graphql/base.graphqls")
            .resolvers(new Query(), new Mutation())
            .file("graphql/item.graphqls")
            .resolvers(new ItemResolver(itemService))
            .build()
            .makeExecutableSchema();
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }
}

The schema files define the GraphQL types. base.graphqls declares the root Query and Mutation with a simple version field. item.graphqls extends these roots with item‑related queries and mutations and defines Item, ItemList, and Param types.

schema {
    query: Query
    mutation: Mutation
}

type Query {
    version: String
}

type Mutation {
    version: String
}

extend type Query {
    queryItemList: ItemList
    queryById(id: ID): Item
}

extend type Mutation {
    updateName(param: Param): Item
}

type Item {
    id: ID!
    code: String!
    name: String!
}

type ItemList {
    itemList: [Item!]!
    total: Int!
}

input Param {
    id: ID!
    name: String!
}

The ItemResolver implements GraphQLQueryResolver and GraphQLMutationResolver, delegating the actual work to an IItemService implementation.

public class ItemResolver implements GraphQLQueryResolver, GraphQLMutationResolver {
    private IItemService itemService;

    public ItemResolver(IItemService itemService) {
        this.itemService = itemService;
    }

    // queryItemList defined in item.graphqls
    public ItemList queryItemList() {
        return itemService.queryItemList();
    }

    public Item queryById(Long id) {
        return itemService.queryById(id);
    }

    public Item updateName(Param param) {
        return itemService.updateName(param);
    }
}

A simple GraphqlController exposes a /graphql POST endpoint that builds an ExecutionInput from the incoming GraphqlRequest, executes it with the GraphQL bean, and returns either the data or any errors.

@RestController
@RequestMapping("/graphql")
public class GraphqlController {
    @Autowired
    private GraphQL graphQL;

    @PostMapping
    public Object execute(@RequestBody GraphqlRequest request) {
        ExecutionInput executionInput = ExecutionInput.newExecutionInput()
            .query(request.getQuery())
            .variables(request.getVariables())
            .build();
        ExecutionResult executionResult = graphQL.execute(executionInput);
        List<GraphQLError> errors = executionResult.getErrors();
        if (errors != null && !errors.isEmpty()) {
            Map<String, Object> result = new HashMap<>();
            result.put("errors", errors);
            return result;
        }
        return executionResult.getData();
    }
}

Three example operations are tested: fetching the item list, querying an item by ID, and updating an item's name. The article includes screenshots of the JSON responses showing successful queries and mutations.

With the configuration complete, the project can be started and further business logic added.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendjavaSpring BootAPITutorialGraphQL
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.