How to Build a GraphQL API using Spring Boot

How to Build a GraphQL API using Spring Boot

This article will give an introduction to setting up a GraphQL server using Spring Boot so that it can be added to existing applications or used in new ones.

Introduction

In this tutorial we will build a Pokemon API that consumes data from a Postgres database, with a simple endpoint that performs a search by id.

Postgres setup

If you already have Postgres installed locally, you can skip this part, otherwise the easiest way to do it is by running a Docker image. Just install Docker and then:

docker run -p5432:5432 -d postgres:11.4-alpine

This command will start a Postgres instance on port 5432 with default user postgres and default database postgres.

Spring Boot setup

We will start by creating the initial project files using Spring Initializr. I've selected:

  • Gradle
  • Java
  • Spring Boot 2.1.6
  • Spring Web Starter
  • Spring Data JPA
  • PostgreSQL Driver

Besides Spring dependencies, we need to add the GraphQL libraries:

  • GraphQL Spring Boot Starter: will automatically create an /graphqlendpoint
  • GraphQL Spring Boot Starter Test: for our unit tests
  • GraphQL Java Tools: from its own documentation: "maps fields on your GraphQL objects to methods and properties on your java objects". This library requires version 1.3.* of Kotlin, so you need to create a gradle.properties file on the project root directory with content:
kotlin.version=1.3.10

Database connection

After adding the dependencies, you can edit the src/main/resources/application.properties file to add the Postgres configuration. If you are using the Docker command above to start Postgres locally, your file should be like this:

## PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=

#drop n create table again, good for testing, comment this in production
spring.jpa.hibernate.ddl-auto=create-drop

Run your application to test if everything is working so far: ./gradlew bootRun.

GraphQL Schema

GraphQL has a great schema language that adds type declatarations to its request and return values and couples this to the API implementation. Which means that what you declare on the schema must be implemented.

If we want to add an endpoint to search a pokemon by its id we should declare on src/main/resources/schema.graphqls file:

type Pokemon {
    id: ID!
    name: String!
}

type Query {
    pokemon(id: ID!): Pokemon
}

Our next step now must be the database search of a Pokemon instance by its id, or else the application won't run.

Query resolver

The declared schema expects to returns a Pokemon type that contains required attributes id and name.

To our application, that means Pokemon is a Java class with id and nameproperties but also a database table. We can use javax.persistenceannotations to automatically map Pokemon to database table with columns id and name:

@Entity
@Table(name = "pokemon")
public class Pokemon {

    public Pokemon(final Long id, final String name) {
        this.id = id;
        this.name = name;
    }

    @Id
    public Long id;

    @Column
    public String name;
}

The other expected class should be a Spring Bean that implements GraphQLQueryResolver interface and should have a method with name getPokemon, that matches the parameters and response exactly like we defined in the scheme:

@Component
public class Query implements GraphQLQueryResolver {

    public Pokemon getPokemon(Long id) {
        return new Pokemon(1L, "Pikachu");
    }
}

We can now perform an request at our new endpoint to check if its response is our Pikachu.

GraphiQL

GraphiQL configures an endpoint at our API that allow us to test any query. In our project it will run on address <a href="http://localhost:8080/graphiql" target="_blank">http://localhost:8080/graphiql</a>.

The left column is where we should write the queries, and the right column is the results. For example, if we enter the query:

# Searches a Pokemon with id 25 and returns its field 'name'
query {
  pokemon(id: 25){
    name
  }
}

We should expect the result on right column:

{
  "data": {
    "pokemon": {
      "name": "Pikachu"
    }
  }
}

So far it doesn't matter which parameter id we pass because we've fixed the response object, but now we will implement a database search.

Fetch Pokemons from database

Currently our application is not doing a real database search but returning a fixed instance. Let's now implement this part.

First we create a PokemonRepository interface that extends JpaRepository:

@Repository
public interface PokemonRepository extends JpaRepository<Pokemon, Long> {
}

Then we change our Query class to autowire this bean and perform the real database fetch:

@Component
public class Query implements GraphQLQueryResolver {

    @Autowired
    private PokemonRepository repository;

    public Pokemon getPokemon(Long id) {
        // Not returning a fixed instance anymore
        return repository.findById(id).orElse(null);
    }
}

Unit test

Our automated test will make use of GraphQLTestTemplate class which allow us to enter a query and verify its response. For example, if we want to test the search pokemon by id query, we first have to create a file in src/test/resources with this query:

# src/test/resources/get-pokemon-by-id.graphql
query {
    pokemon(id: "1") {
        id
        name
    }
}

The test class should be annotated with @GraphQLTest so it can resolve the GraphQLTestTemplate instance, and PokemonRepository should be annotated with @MockBean so we can mock its response using Mockito.

@RunWith(SpringRunner.class)
@GraphQLTest
public class DemoApplicationTests {

    @Autowired
    private GraphQLTestTemplate graphQLTestTemplate;

    @MockBean
    private PokemonRepository pokemonRepository;

    @Test
    public void getById() throws IOException {
        Pokemon pokemon = new Pokemon(1L, "Pikachu");
        when(pokemonRepository.findById(any()))
                .thenReturn(Optional.of(pokemon));

        GraphQLResponse response =
                graphQLTestTemplate.postForResource("get-pokemon-by-id.graphql");

        assertTrue(response.isOk());
        assertEquals("1", response.get("$.data.pokemon.id"));
        assertEquals("Pikachu", response.get("$.data.pokemon.name"));
    }
}

Basically the scenario we are testing here is the following:

  • Given the repository returns a pikachu when called the findByIdmethod
  • When we query GraphQL Api with get-pokemon-by-id.graphql
  • Then we expect the response to be a JSON containing the pikachu from repository

    Conclusion

The challenge of implementing a GraphQL Api using Spring Boot relies mostly in the configuration and small details of Spring Boot functionality. Overall I think the integration works very well, specially the GraphQL Java Tools that enforces the code implementation.

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

Spring & Hibernate for Beginners (includes Spring Boot)

Spring Framework Master Class - Learn Spring the Modern Way!

Master Microservices with Spring Boot and Spring Cloud

Spring Boot and OAuth2: Getting the Authorization Code

Monitor Your Java Apps with Spring Boot Actuator

An Introduction to Spring Boot

How to build GraphQL APIs with Kotlin, Spring Boot, and MongoDB?

Build a Rest API with Spring Boot using MySQL and JPA

Angular 8 + Spring Boot 2.2: Build a CRUD App Today!

Spring Boot vs. Spring MVC vs. Spring: How Do They Compare?

Top 4 Spring Annotations for Java Developer in 2019

spring-boot java graphql docker

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Top 10 Advanced Java and Spring Boot Courses for Full-Stack Java Developers

These are best online courses to learn Spring Boot, Advanced Java, Docker, React, Microservices, DEvops, and Angular to become full stack Java developer.

How to Build a GraphQL API with Java and Spring Boot

In this tutorial, I’ll show you how to use Java and Spring Boot to build a GraphQL API. How to GraphQL in Java. Create a GraphQL API with Java and Spring Boot. Run Your Java GraphQL API. Test Your Java GraphQL API with JUnit 5. Secure Your Java GraphQL API. Further Reading on GraphQL and Java.

Build a Java 8 Spring Boot App with Docker

Build a Java 8 Spring Boot App with Docker - In this article, I am going to show you how to develop and run a simple Spring web application using Java 8 without installing Java 8 on your local machine.

How to Install OpenJDK 11 on CentOS 8

What is OpenJDK? OpenJDk or Open Java Development Kit is a free, open-source framework of the Java Platform, Standard Edition (or Java SE).

Two Ways to Dockerize Spring Boot Applications

This article looks at two common options for Dockerizing Spring Boot applications. We will use a simple REST application as a running example.