DEV Community

Sam Benskin
Sam Benskin

Posted on • Updated on

How to Build GraphQL Services in Java with Spring Boot

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

Inside that, create a file

GraphQLSpringBootTutorialApplication.java
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And Create this file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/enums/Animal.java
Enter fullscreen mode Exit fullscreen mode

And here's the content

package uk.co.benskin.graphql_spring_boot_tutorial.enums;

public enum Animal {
    DOG,
    CAT,
    BADGER,
    MAMMOTH
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Create this file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/entities/Pet.java
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And create the file

src/main/java/uk/co/benskin/graphql_spring_boot_tutorial/resolvers/Query.java
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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"
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

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 :)

Top comments (22)

Collapse
 
hugecoderguy profile image
Christian Kreiling

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?

Collapse
 
sambenskin profile image
Sam Benskin

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.

Collapse
 
ialserdamatrik profile image
Ivo

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.

Collapse
 
gilyaary profile image
gilyaary

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!!!!

Collapse
 
sambenskin profile image
Sam Benskin

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

Collapse
 
biggo6 profile image
Joram Kimata

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

Collapse
 
sambenskin profile image
Sam Benskin

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

Collapse
 
acedrow profile image
Linden Holt

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

Collapse
 
sambenskin profile image
Sam Benskin

Thank you 😀

Collapse
 
naveenpop profile image
naveenp

I've written mine after looking at this post.

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

Collapse
 
devlopix profile image
devlopix

Thank you man !

Collapse
 
sambenskin profile image
Sam Benskin

You're welcome 😀

Collapse
 
khteh profile image
Teh Kok How

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

Collapse
 
sambenskin profile image
Sam Benskin

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

Collapse
 
naveenpop profile image
naveenp

Awesome :)

Collapse
 
sambenskin profile image
Sam Benskin

Thanks 😀

Collapse
 
rolfed profile image
Danniel Rolfe

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.

Collapse
 
sambenskin profile image
Sam Benskin

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

Collapse
 
sunnyagarwal008 profile image
sunnyagarwal008

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

Collapse
 
sambenskin profile image
Sam Benskin

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

Collapse
 
abdel777 profile image
abdellah Frindou

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

Collapse
 
abdel777 profile image
abdellah Frindou • Edited

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.