Getting started with Spring for GraphQL
In this tutorial, you will create a GraphQL server in Java using Spring for GraphQL in 3 minutes. It requires a little Spring and Java knowledge. While we give a brief introduction to GraphQL, the focus of this tutorial is developing a GraphQL server in Java.
If you're looking to learn more after this tutorial, we (the maintainers) have written a book! GraphQL with Java and Spring includes everything you need to know to build a production ready GraphQL service with Spring for GraphQL, the official Spring integration built on top of the GraphQL Java engine. It's available on Leanpub and Amazon.
A very short introduction to GraphQL
GraphQL is a query language to retrieve data from a server. It is an alternative to REST, SOAP or gRPC.
Let's suppose we want to query the details for a specific book from an online store backend.
With GraphQL you send the following query to the server to get the details for the book with the id "book-1":
query bookDetails {
bookById(id: "book-1"){
id
name
pageCount
author {
firstName
lastName
}
}
}
This is not JSON (even though it looks deliberately similar), it is a GraphQL query. It basically says:
- query a book with a specific id
- get me the id, name, pageCount and author from that book
- for the author, I want to know the firstName and lastName
The response is normal JSON:
{
"bookById": {
"id":"book-1",
"name":"Harry Potter and the Philosopher's Stone",
"pageCount":223,
"author": {
"firstName":"Joanne",
"lastName":"Rowling"
}
}
}
One very important property of GraphQL is that it is statically typed: the server knows exactly the shape of every object you can query and any client can actually "introspect" the server and ask for the "schema". The schema describes what queries are possible and what fields you can get back. (Note: when we refer to schema here, we always refer to a "GraphQL Schema", which is not related to other schemas like "JSON Schema" or "Database Schema")
The schema for the above query looks like this:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
This tutorial will focus on how to implement a GraphQL server with this schema in Java.
We've barely scratched the surface of what's possible with GraphQL. Further information can be found on the official GraphQL page.
GraphQL Java Overview
GraphQL Java is the Java (server) implementation for GraphQL. There are several repositories in the GraphQL Java Github org. The most important one is the GraphQL Java Engine which is the basis for everything else.
The GraphQL Java Engine is only concerned with executing queries. It doesn't deal with any HTTP or JSON related topics. For these aspects, we will use Spring for GraphQL which takes care of exposing our API via Spring Boot over HTTP.
The main steps of creating a GraphQL Java server are:
- Defining a GraphQL Schema.
- Deciding on how the actual data for a query is fetched.
Our example API: getting book details
Our example app will be a simple API to get details for a specific book. This is in no way a comprehensive API, but it is enough for this tutorial.
Create a Spring Boot app
The easiest way to create a Spring Boot app is to use the Spring Initializr.
Select:
- Gradle Project
- Spring Boot 3
- Java 17 or higher
For the project metadata, use:
- Group:
com.graphqljava.tutorial - Artifact:
bookDetails
For dependencies, select:
- Spring Web, and
- Spring for GraphQL
Then click on Generate for a ready to use Spring Boot app.
All subsequently mentioned files and paths will be relative to this generated project.
Spring for GraphQL adds many useful features including loading schema files, initializing GraphQL Java, and simplifying data fetching with controller annotations.
Schema
Add a new file schema.graphqls to src/main/resources/graphql with the following content:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
This schema defines one top level field (in the type Query): bookById which returns the details of a specific book.
It also defines the type Book which has the fields: id, name, pageCount and author.
author is of type Author, which is defined after Book.
The Domain Specific Language (shown above) used to describe a schema is called the Schema Definition Language or SDL. More details about it can be found here.
Source of the data
To simplify the tutorial, book and author data will come from static lists inside their respective classes. It is very important to understand that GraphQL doesn't dictate in any way where the data comes from. This is the power of GraphQL: it can come from a static in-memory list, from a database or an external service.
Create the Book class
Add the following to bookDetails/Book.java
package com.graphqljava.tutorial.bookDetails;
import java.util.Arrays;
import java.util.List;
record Book(String id, String name, int pageCount, String authorId) {
private static List<Book> books = Arrays.asList(
new Book("book-1", "Harry Potter and the Philosopher's Stone", 223, "author-1"),
new Book("book-2", "Moby Dick", 635, "author-2"),
new Book("book-3", "Interview with the vampire", 371, "author-3")
);
public static Book getById(String id) {
return books.stream().filter(book -> book.id().equals(id)).findFirst().orElse(null);
}
}
Create the Author class
Add the following to bookDetails/Author.java
package com.graphqljava.tutorial.bookDetails;
import java.util.Arrays;
import java.util.List;
record Author(String id, String firstName, String lastName) {
private static List<Author> authors = Arrays.asList(
new Author("author-1", "Joanne", "Rowling"),
new Author("author-2", "Herman", "Melville"),
new Author("author-3", "Anne", "Rice")
);
public static Author getById(String id) {
return authors.stream().filter(author -> author.id().equals(id)).findFirst().orElse(null);
}
}
Adding code to fetch data
Spring for GraphQL provides an annotation-based programming model to declare handler methods to fetch the data for specific GraphQL fields.
Add the following to bookDetails/BookController.java