loading...

How to Build GraphQL Services in Java with Spring Boot

sambenskin profile image Sam Benskin Updated on ・7 min read

NOTE: Please be aware this article is now out of date as the tech has moved on since I wrote it in 2019.

Let's start by taking a quick look at the tech involved.

GraphQL

Compared to REST, GraphQL is the new kid on the block, but I think the improvements are so big that I'm moving any new APIs I write to use it. I've seen so many APIs that returned huge amounts of data when all the user needed was a set of identifiers to loop through and query a second endpoint for some other data related to those identifiers, which highlights the second issue. Just writing that sounds mad, I just want to make one call to the API and get everything and only what I need.

I won't go into much detail on why GraphQL is better, there's lots of articles out there that will let you decide that for yourself. All I will say is, there are two big reasons I've decided to make the switch: the ability to easily include in your request the structure of the data you want to receive; and the ability to combine what would have been multiple REST requests into a single GraphQL query. Both are huge improvements over REST. Sure, you could try and write your REST endpoints this way, but then they really wouldn't be REST anymore and GraphQL is built to work this way.

Ok now that is out of the way, let's get on with writing some code. We're going to build a simple barebones GraphQL API in Java using Spring Boot

Spring Boot

Coming from a largely PHP background, I've only recently discovered the joy of the Spring framework and Spring Boot in particular. It makes setting up a new project extremely easy; taking an opinionated view of how to configure and structure a lot of the traditional boilerplate code for controllers, data access, etc, but will get out of the way when you want to configure it how you want. In this example, we won't need to write any controllers; just our entity model, types and the GraphQL schema.

Pre-requisites

For this project, we're going to use Java 8, I tried with Java 10 and then 9, but there's an issue with the lombok dependancy so had to fallback to 8 for this tutorial. I'll update it to 10 when that's fixed. We'll use Spring Boot 2 which uses version 5 of the Spring Framework and sets it all up for you. For simplicity, we'll also use the Maven build framework for managing our java dependencies. We'll also use the excellent GraphQL-Java library spring boot starter to give us the GraphQL and GraphIQL endpoints (more on that later). Finally, I've added Project Lombok which allows you to annotate classes, methods, variables, etc to provide boilerplate functionality.

Here are the exact versions I'll be using:

Let's Go!

First of all, create a new folder and open it in your chosen IDE. I'm using Microsoft Visual Studio Code. It really is the best free code editor out there, sorry Atom.

Create a new file called pom.xml and put this inside:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>uk.co.benskin</groupId>
    <artifactId>graphql_spring_boot_tutorial</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>graphql_spring_boot_tutorial</name>
    <description>Learn how to build a graphql spring boot based java service</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>4.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
    </dependencies>
</project>

The above file defines our project in the first half, so change the project name, description, etc to your own project details. In the second half, we've defined six dependencies:

  • Spring Boot Web - provides the functionality to support our endpoints through web protocols
  • Spring Boot DevTools - useful for development building and debugging
  • GraphQL-Java Tools - Loads and powers our GraphQL schema
  • GraphQL-Java Spring boot starter for GraphQL - hosts our schema at the /graphql endpoint in our spring context
  • GraphQL-Java Spring boot starter for GraphIQL - a web based UI for interacting with the /graphql endpoint, with knowledge of the schema at the endpoint
  • Project Lombok for reducing boilerplate in our java code

Go ahead and install all the dependencies

mvn install

After a large list of output from installing the dependencies for the first time, you should see a message that says "BUILD SUCCESS".

Ok, now we've got everything we need to get started.

Create a folder

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/

Inside that, create a file

GraphQLSpringBootTutorialApplication.java

Put the following contents

package uk.co.benskin.graphql_spring_boot_tutorial;

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

@SpringBootApplication
public class GraphQLSpringBootTutorialApplication {

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

This loads up a new Spring Applicaton Context integrated automagically with our GraphQL-Java starter dependancies.

Now let's try starting our app and see what we get

mvn spring-boot:run

You should see a lot of info output and hopefully a few lines saying

INFO 64612 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
INFO 64612 --- [  restartedMain] b.g.GraphQLSpringBootTutorialApplication : Started GraphQLSpringBootTutorialApplication in 4.886 seconds (JVM

Now open a browser and go to http://localhost:8080

You should see an error page like this

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

[DATE]
There was an unexpected error (type=Not Found, status=404).
No message available

This is good! the server is running but we've not told how to respond to requests at the root "/", so now try http://localhost:8080/graphiql and you should see a nice UI for interacting with your (yet-to-be-built) endpoint.

Building the GraphQL Schema

Now onto the fun part, the GraphQL schema. I won't go into much detail on how GraphQL works, please take a look at GraphQL tutorials for that.

Create this file

src/main/resources/petshop.graphqls

And put in the contents below

type Query {
    pets: [Pet]
}

type Pet {
    id: Int
    type: Animal
    name: String
    age: Int
}

enum Animal {
    DOG
    CAT
    BADGER
    MAMMOTH
}

Above we've defined the main Query which will return "pets" as an array of Pet types. The type of the Pet is an enum of type Animal, defined below it.

Building the API

Moving back to the java code now. We're going to create a few folders to help us organsie our code. There's no restriction on what you can call these and where you put them, but I strongly suggest you use subfolders to better organise your code, countless future developers will thank you.

Create this folder

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/enums

And Create this file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/enums/Animal.java

And here's the content

package uk.co.benskin.graphql_spring_boot_tutorial.enums;

public enum Animal {
    DOG,
    CAT,
    BADGER,
    MAMMOTH
}

That's defined our enum, now onto the Pet entity model

Create this folder

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/entities

Create this file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/entities/Pet.java

And here's the contents

package uk.co.benskin.graphql_spring_boot_tutorial.entities;

import lombok.Data;
import uk.co.benskin.graphql_spring_boot_tutorial.enums.Animal;

@Data
public class Pet {
    private long id;

    private String name;

    private Animal type;

    private int age;
}

This is a simple POJO with an @Data annotation to take care of the boilerplate getters, setters and the constructor.

Now make the directory for the GraphQL resolvers

src/main/java/uk/co/benskin/graphql-spring-boot-tutorial/resolvers

And create the file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/resolvers/Query.java

And fill it with this

package uk.co.benskin.graphql_spring_boot_tutorial.resolvers;

import java.util.ArrayList;
import java.util.List;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Component;
import uk.co.benskin.graphql_spring_boot_tutorial.entities.Pet;
import uk.co.benskin.graphql_spring_boot_tutorial.enums.Animal;

@Component
public class Query implements GraphQLQueryResolver {

    public List<Pet> pets() {
        List<Pet> pets = new ArrayList<>();

        Pet aPet = new Pet();
        aPet.setId(1l);
        aPet.setName("Bill");
        aPet.setAge(9);
        aPet.setType(Animal.MAMMOTH);

        pets.add(aPet);

        return pets;
    }
}

Ok, that should be everything we need to call our GraphQL endpoint to get a list of pets (one in this case)

Restart your build by stopping maven (ctrl/cmd + c) and starting it again using mvn spring-boot:run

To see it running, go to http://localhost:8080/graphiql and you'll get a nice UI to play around with. Again I won't go into much detail on how to use the GraphIQL interface.

In the box just below the GraphIQL title, to the right of the History box, is where you enter the request. Copy and paste the below there:

{
    pets {
        name
        age
        type
    }
}

Then click the play icon (next to the GraphIQL title). You should see a reponse like below:

{
    "data": {
        "pets": [
            {
                "name": "Bill",
                "age": 9,
                "type": "MAMMOTH"
            }
        ]
    }
}

Congratulations! You've just written a GraphQL service in Java and SpringBoot. Ok so it's not going to return anything else apart from that one record, so in Part 2, we introduce database access through the Spring Data project which utilises the Java Persistence API (JPA)

Thank you very much for reading this article! If you liked it, please comment to let me know or if you have any suggestions for improvements; and make sure to click the heart/unicorn/bookmark buttons below, I always really appreciate it :)

Posted on by:

sambenskin profile

Sam Benskin

@sambenskin

Software Engineering Lead with a passion for Product, Agile and all things Dev and DevOps

Discussion

markdown guide
 

Hey Sam, I've written Java webapps with spotify/apollo before but haven't used Spring. This was a helpful introduction to Spring and the ease of creating a GraphQL server, but do you have any resources for learning Spring / Spring Boot quickly and effectively?

 

Thank you for the kind words. As far as resources, I always use Google to search for answers to the problems I have but more often than not I'll see an article on baeldung.com that is always well written, well layed out and succinct so I would check that site out if I were you. Of course dev.to has many brilliant articles so I'm sure you'll find something here too.

 

Hi Sam, very clear written example, thanks. Do you also have a nice example of a Spring Boot Graphql client project to connect to this graphql server. I see a lot of graphql client projects written in NodeJS, Android and iOS but it is hard to find it in java. I think this is because graphql is meant to use it from a frontend framework ( like apollo for android ) and it is not common to use it from a java backend environment.

 

This is the best tutorial so far. A to B with no extra clutter. I was able to quickly setup, understand and run the example code.
Very Well Done!!!!

 

Thank you 😀 I'm glad it's helped you getting started

 

Thanks for good tutorial, was awesome one but i wonder if you will share with us advanced features of graphql with java like mutation and subscription concepts

 

Thanks, I haven't written anything yet but I'll definitely consider it.

 

Concise and educational tutorial. Gives you everything you need and nothing else, and it works like a charm. Love it.

 
 

I've written mine after looking at this post.

github.com/nkumarclm/graphql-sample - Graph QL to stitch 2 Rest APIs

 
 

Deploying the application as WAR to tomcat server 9 causes exception: github.com/graphql-java-kickstart/...

 

Sorry I've not tried that, hope you find the issue and can report back to help anyone else in the same situation

 
 

Hey Sam,
This is a really well written tutorial. I'm working on learning GraphQL and this was the perfect introduction. Keep up the great work.

 

Thank you, that's very kind of you to say

 

How do we define graphql schema with query variables in this example?

 

Sorry but that's out the scope of this article. I'll try to include it in a future article so.please follow me if you want to be notified when I publish it

 

Hello, thanks for your article. i followed the same instructions but i dont get the results. the url localhost:8080/graphiql shows an error

 

it works now, it was enough to write localhost:8080 without adding /graphiql. but can you please explain more how that happend. i mean just writing petshop.graphqls and the resolvers and that was enough to get the data. How the process is that he know this file(petshop.graphqls) and parse it to a java Object. is it possible to add more .graphqls files and interaction between them.