Beginner’s Guide to GraphQL with Spring Boot

Reading Time: 4 minutes

The world is a stage where all of us are artists. Constant learning is the foundation of success. So here we are going to have a tutorial on GraphQL in which we will see how to create a GraphQL server in Java.

Objective

We are going to query the details for a specific song from an online platform.

Prerequisite

Basic knowledge of:
– Spring Boot
– Java
– Maven

Overview

GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. 

Creating Application

Step 1(Create Spring Boot App):

We can easily create a spring boot app by using https://start.spring.io/

Just chose appropriate options as per yourself and select WEB as dependency in dependencies section.
After clicking on Generate Project tab your Spring Boot App will be downloaded as jar.

Step 2(Adding Dependencies in pom):

We will only add GraphQL dependency and Guava(because it will make easy to read resources) dependency.

Dependencies will look like:

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java</artifactId>
            <version>14.1</version>
        </dependency>

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-spring-boot-starter-webmvc</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.5-jre</version>
        </dependency>
Step 3(Create a Schema):
Schema:

GraphQL API has a schema which defines each field that can be queried.
We will create schema in src/main/resources and will name it as schema.graphqls

type Query {
    songById(id: ID): Song
}

type Song {
    id: ID
    name: String
    genre: String
    artist: Artist
}

type Artist {
    id: ID
    firstName: String
    lastName: String
}

It is not JSON (even though it looks deliberately similar), it is a GraphQL schema. It defines each field that can be queried or mutated and what types those fields are. We are only going to look for query part in this blog.

In code, we have defined a type Query at top which defines that we are going to query for the fields mentioned in there( in our case, query for a song with specific Id named as songById). songById is again of type Song whose fields are defined there. In type Song we can also see that there is a field artist which is of another type Artist which you also can see there.
So that’s how we can create nested schema. There is a lot to know about schema which we will see later.

Step 4(Fetching Data)
Data Fetchers

Data Fetcher is probably the most important concept for a GraphQL. 
It is an interface with a single method, taking a single argument of type:

public interface DataFetcher<T> {
    T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
}

A Data Fetcher is used to fetch data when it is executed in query. And whenever a query is executed GraphQL calls appropriate DataFetcher to get the data.
So in our case first we will create a class in which we are going to add static data and will fetch them using DataFetcher.

@Component
public class GraphQLDataFetchers {

    private static List<Map<String, String>> song = Arrays.asList(
            ImmutableMap.of("id", "song-1",
                    "name", "Shape of you",
                    "genre", "Pop",
                    "artist", "artist-1"),
            ImmutableMap.of("id", "song-2",
                    "name", "Closer",
                    "genre", "Electronic/Dance",
                    "artist", "artist-2"),
            ImmutableMap.of("id", "song-3",
                    "name", "Señorita",
                    "genre", "Pop",
                    "artist", "artist-3")
    );

    private static List<Map<String, String>> artist = Arrays.asList(
            ImmutableMap.of("id", "artist-1",
                    "firstName", "Ed",
                    "lastName", "Sheeran"),
            ImmutableMap.of("id", "artist-2",
                    "firstName", "ChainSmokers",
                    "lastName", ""),
            ImmutableMap.of("id", "artist-3",
                    "firstName", "Shawn/Camila",
                    "lastName", "Mendes/Cabello")
    );

    public DataFetcher getSongByIdDataFetcher() {
        return dataFetchingEnvironment -> {
            String songID = dataFetchingEnvironment.getArgument("id");
            return song
                    .stream()
                    .filter(book -> book.get("id").equals(songID))
                    .findFirst()
                    .orElse(null);
        };
    }

    public DataFetcher getArtistByIdDataFetcher() {
        return dataFetchingEnvironment -> {
            Map<String, String> song = dataFetchingEnvironment.getSource();
            String artistID = song.get("artist");
            return artist
                    .stream()
                    .filter(payment -> payment.get("id").equals(artistID))
                    .findFirst()
                    .orElse(null);
        };
    }
}

This is the final draft of class which will help us in fetching data.

Step 5(Create GraphQL Instance)

Now we have schema, and data fetchers so we can now create a controller to call them.
So we are going to make a class name GraphQLProvider, in which we are going to create bean, integrate schema, and call data fetchers:

@Component
public class GraphQLProvider {

    @Autowired
    private GraphQLDataFetchers graphQLDataFetchers;
    private GraphQL song;

    @Bean
    public GraphQL song() {
        return song;
    }

    @PostConstruct
    public void init() throws IOException {
        URL url = Resources.getResource("schema.graphqls");
        String sdl = Resources.toString(url, Charsets.UTF_8);
        GraphQLSchema graphQLSchema = buildSchema(sdl);
        this.song = GraphQL.newGraphQL(graphQLSchema).build();
    }

    private GraphQLSchema buildSchema(String sdl) {
        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
        RuntimeWiring runtimeWiring = buildWiring();
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
    }

    private RuntimeWiring buildWiring() {
        return RuntimeWiring.newRuntimeWiring()
                .type(newTypeWiring("Query")
                        .dataFetcher("songById", graphQLDataFetchers.getSongByIdDataFetcher()))
                .type(newTypeWiring("Song")
                        .dataFetcher("artist", graphQLDataFetchers.getArtistByIdDataFetcher()))
                .build();
    }

}

Here we have used init() method to create a GraphQL instance and a GraphQLSchema to integrating with schema.
We created a bean to expose GraphQLinstance as a Spring Bean via the graphQL(). The GraphQL Java Spring adapter will use that GraphQL instance to make our schema available via HTTP on the default url “/graphql”.
What have used buildSchema method which creates the GraphQLSchema instance and wires in code to fetch data.
TypeDefinitionRegistry Type is the parsed version of our schema file. SchemaGerator combines the TypeDefinitionRegistry with RuntimeWiring to actually make our GraphQLSchema. builWiring uses the graphQLDataFetchers bean to actually register two DataFetchers:
– One to retrieve a song with a specific ID
– One to get the artist for a specific song.

Step 6(Run)

This is all we have to do. Now simply run your service.
We have used post-construct annotation, so it will be POST endpoint
By default your service run on ” http://localhost:8080/graphql “.
You can implement various queries and see how it is working.

Working with Postman

While writing the query in postman will be quite challenging as the schema is not JSON type. So we write like this:

{
    "query": "query{songById(id: \"song-1\"){id, name, genre artist{firstName, lastName }}}"
}
  • whole query should be in single line
  • there should be a key named as “query” and it’s value should always start from “query”.
  • Inside query first thing would be the writing what we have written in schema. Like, songById(id: “song-1”).
  • We will write nested schema as written. i.e, inside “curly braces{}”. Like, {id, name, artist{firstName}}.

That’s pretty much it from the article, full code can be found on the My GitHub Repo , feel free to fork it. If you have any feedback or queries, please do let me know in the comments. Also, if you liked the article, please give me a thumbs up and I will keep writing blogs like this for you in the future as well. Keep reading and Keep coding.

Reference

Knoldus-blog-footer-image

Leave a Reply