Spring Boot GraphQL tutorial
When a request is made to a REST
service, it sends data for only that service with all the fields. But what if only a
subset of data is required in the response or response should contain multiple resource data ? For example if request is made to get
User and we want only subset of data along with User Address, then we can make a GraphQL
query.
A GraphQL
query will select only the fields required in the response and also save multiple REST calls to a service.
This tutorial shows how to query an API using Spring Boot
& GraphQL
.
Step 1) Add below dependencies in pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-spring-boot-starter</artifactId> <version>5.0.2</version> </dependency> <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>
Step 2) Create User POJO, UserRepository and UserService classes
UserService will make call to UserRepository class and get users details.
package com.example.demo; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; private int id; private String email; private String firstName; private String lastName; // removed getter and setters }
package com.example.demo; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.springframework.stereotype.Repository; @Repository() public class UserRepository { private Map<Integer, User> users = new HashMap<>(); public Collection<User> findAll() { return users.values(); } public Optional<User> findUser(Integer userId) { return Optional.ofNullable(users.get(userId)); } public User addUser(int id, User user) { users.put(id, user); return user; } public void deleteItem(Integer id) { users.remove(id); } public void updateUser(Integer id, User user) { users.put(id, user); } }
package com.example.demo; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserRepository userRepository; public User createUser(final int id, final String email, final String firstName, final String lastName) { return userRepository.addUser(id, new User(id, "harry@hotmail.com", "Harry", "Potter")); } public List<User> getAllUsers(final int count) { return userRepository.findAll().stream().limit(count).collect(Collectors.toList()); } public Optional<User> getUser(final Integer id) { return userRepository.findUser(id); } }
Step 3) Create GraphQL schema file to query the API
Create a GraphQL
schema file under src/main/resources
folder which is written in SDL (Schema Definition Language).
It provides the schema that describes the APIs. Note that GraphQL
schema can contain only one root Query & one Mutation.
type User { id: Int, email: String, firstName: String, lastName: String } type Query { users(count: Int):[User] user(id: String):User } type Mutation { createUser(id: Int!, email: String, firstName: String, lastName: String):User }
Step 4) Create GraphQLApplication, UserQuery, UserMutation, classes
package com.example.demo; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class GraphQLApplication { public static void main(String[] args) { SpringApplication.run(GraphQLApplication.class, args); } @Bean public ApplicationRunner userInitializer(UserRepository userRepository) { return args -> { userRepository.addUser(1, new User(1, "harry@hotmail.com", "Harry", "Potter")); }; } }
To handle the queries defined in GraphQL
schema, we need to add Query & Mutation Resolvers. When a query is made, UserQuery
will process it, while if want to add a record or make a mutation, it will be handled by UserMutation
.
package com.example.demo; import java.util.List; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.coxautodev.graphql.tools.GraphQLQueryResolver; @Component public class UserQuery implements GraphQLQueryResolver { @Autowired private UserService userService; public List<User> getUsers(final int count) { return this.userService.getAllUsers(count); } public Optional<User> getUser(final Integer id) { return this.userService.getUser(id); } }
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.coxautodev.graphql.tools.GraphQLMutationResolver; @Component public class UserMutation implements GraphQLMutationResolver { @Autowired private UserService userService; public User createUser(final int id, final String email, final String firstName, final String lastName) { return userService.createUser(id, email, firstName, lastName); } }
Step 5) Running GraphQLApplication
You will see GraphQL user interface where you can run queries. Run below queries and see result
query { users(count: 2) { id email firstName lastName } }
Query Result
{ "data": { "users": [ { "id": 1, "email": "harry@hotmail.com", "firstName": "Harry", "lastName": "Potter" } ] } }
mutation { createUser(id: 2, email: "sfdsf@sdfsdf", firstName: "XYZ", lastName: "sdfd") { id } }
Mutation Result
{ "data": { "createUser": { "id": 2 } } }
References :
GraphQL core concepts