GraphQL tutorial for Spring Boot developers

GraphQL is a specialized query language which gives us an alternative a more flexible approach to managing data in our application than restful design. In this tutorial we will learn how to use GraphQL with a Spring Boot application.

 First, let’s think about how a REST API might be structured: so typically we’d set up specific URLs or endpoints in our API to control different pieces of data for example authors books now from the front-end what we do is would make

several different Ajax requests to these different endpoints to retrieve information about those different pieces of data for example authors now whenwe’re using Graph QL we don’t have to worry about setting up these different endpoints or making different requests to all these different endpoints instead what we do is we have just one single supercharged end point where we’ve mapped all of our data onto what isessentially a kind of graph.

 The idea here is that we can then jump in to thisgraph at different points from our application right and we can land on this graph at different points like this

then when we’re in the graph we can walk to related data to get that data and send it back as part of that request so for example let’s consider the following relation:

The GraphQL Query below will fetch all the users and their publicly visible todos:

 query {    users {      name      todos {        title      }    }  } 

The Mutation is the second kind of “root type” which lets us write data to the DB. Think of Mutation as analogous to POST and PUT requests of REST. Let’s look at an example:

mutation createUser{   addUser(fname: "John", age: 34) {     id   } } 

What this means is, we are defining a mutation called “createUser” that adds a user with fname, “Richie” and age, “22”. The response type of this mutation is the function body. It responds with a JSON with the id of the posted data.

data : {   addUser : "a21c2h" } 

The third type of operation available in GraphQL is Subscription. A subscription gives the client the ability to listen to real-time updates on data. Subscriptions use web sockets under the hood. Let’s take a look at an example:

subscription listenLikes {   listenLikes {     fname     likes   } } 

The above subscription responds with the list of users with their first name and number of likes whenever the like count of the user changes.

Setting up a GraphQL Server with Spring Boot

We will start from Spring Command Line Interface. You can however surf to the Spring Initializr Web application if you prefer.

Our Web application, named graphql-demo, will require the following dependencies as specified by spring init:

$ spring init -dweb,data-jpa,h2   graphql-demo 

In addition to the dependencies which have already been created, add the following ones which are needed for GraphQL:

<?xml version="1.0" encoding="UTF-8"?><project>
   <dependency>
           
      <groupId>com.graphql-java</groupId>
           
      <artifactId>graphql-java-tools</artifactId>
           
      <version>5.2.4</version>
       
   </dependency>
    
   <dependency>
           
      <groupId>com.graphql-java</groupId>
           
      <artifactId>graphiql-spring-boot-starter</artifactId>
           
      <version>5.0.2</version>
       
   </dependency>
    
</project>

Now, let’s design our GraphQL schema first:

type Item { 	id: ID!, 	type: String, 	model: String, 	price: Int! }  type Query { 	items(count: Int):[Item] 	item(id: ID):Item }  type Mutation { 	createItem(type: String!, model: String!, price: Int!):Item } 

As you can see, we have basically defined (using a JSON-like syntax):

  • An Item definition with some properties
  • How to Query for Item objects with a specific id
  • How to create a new Item using a Mutation

Now let’s create the model object at first, which is an @Entity objects so they will represent the database’s tables. To reduce boilerplate code, we’re using lombok library in it:

package com.masterspringboot.graphql.dao.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
import java.io.Serializable;

@Data
@EqualsAndHashCode
@Entity
public class Item implements Serializable {
  private static final long serialVersionUID = 1L;

  @Id
  @Column(name = "ID", nullable = false)
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int id;

  @Column(name = "type", nullable = false)
  private String type;

  @Column(name = "model", nullable = false)
  private String model;

  @Column(name = "price")
  private int price;
}

Along with Entity field resolvers, it is required to have Query Resolvers and Mutation Resolvers.

Let’s start implementing the GraphQL Query Resolver:

package com.masterspringboot.graphql.query;

import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.masterspringboot.graphql.dao.entity.Item;
import com.masterspringboot.graphql.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;

@Component
public class ItemQuery implements GraphQLQueryResolver {
  @Autowired private ItemService itemService;

  public List<Item> getItems(final int count) {
    return this.itemService.getAllItems(count);
  }

  public Optional<Item> getItem(final int id) {
    return this.itemService.getItem(id);
  }
}

GraphQLQueryResolver is a marker interface that tells the underlying library to use this bean for resolving queries and will automatically match the getItem/getItems method with the item/items query.

Also, please note that comparing to REST APIs, resolvers work pretty much the same as controllers. Hence, business logic should not be implemented in resolvers, but rather in the service layer, in our case the ItemService class.

Now let’s add also the GraphQLMutationResolver, which is quite similar to the QueryResolver, it just works like a POST request in REST applications, so it is used to add a new Item:

package com.masterspringboot.graphql.mutation;

import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import com.masterspringboot.graphql.dao.entity.Item;
import com.masterspringboot.graphql.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ItemMutation implements GraphQLMutationResolver {
  @Autowired private ItemService itemService;

  public Item createItem(final String type, final String model, final int price) {
    return this.itemService.createItem(type, model, price);
  }
}

For completeness, let’s include also the ItemService class which reads and stores Item objects from the ItemRepository:

package com.masterspringboot.graphql.service;
import com.masterspringboot.graphql.dao.repository.ItemRepository;
import com.masterspringboot.graphql.dao.entity.Item;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class ItemService {
  private final ItemRepository itemRepository;
  public ItemService(final ItemRepository: itemRepository) {
    this.itemRepository = itemRepository;
  }
  @Transactional public Item createItem(final String type, final String model, final int price) {
    final Item item = new Item();
    item.setType(type);
    item.setModel(model);
    item.setPrice(price);
    return this.itemRepository.save(item);
  }
  @Transactional(readOnly = true) public List < Item > getAllItems(final int count) {
    return this.itemRepository.findAll().stream().limit(count).collect(Collectors.toList());
  }
  @Transactional(readOnly = true) public Optional < Item > getItem(final int id) {
    return this.itemRepository.findById(id);
  }
}

And here is the basic ItemRepository interface:

package com.masterspringboot.graphql.dao.repository;

import com.masterspringboot.graphql.dao.entity.Item;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ItemRepository extends JpaRepository<Item, Integer> {}

To run our Application, we will also need a main class:

package com.masterspringboot.graphql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

Run the application and go to http://localhost:8080/graphql/schema.json. You should see a description of the GraphQL schema, something like this:

	 data	 __schema	 queryType	 name	"Query" mutationType	 name	"Mutation" subscriptionType	null types	[…] directives	[…] 

Now, let’s run the GraphQL console which is availabla at: http://localhost:8080/graphiql

Execute first the following mutation, will will create a new Item:

mutation {   createItem (type: "Computer", model:"Asus", price: 500)   {     id   } } 

Let’s check with a Query the list of Item objects:

query {   items(count: 1)    {     id,      type,      model,     price 	} } 

As you can see, we managed to set up a GraphQL server with a Spring Boot application which uses an ItemQuery and a GraphQLQueryResolver to perform Query and a ItemMutation implementing a GraphQLMutationResolver to create a new Item.

Source code available here: https://github.com/fmarchioni/masterspringboot/tree/master/nosql/graphql-demo