DEV Community

Abhay
Abhay

Posted on • Updated on

How to create a GraphQL API using Spring Boot – A Beginner's Guide

What is GraphQL?

According to its official documentation, “GraphQL is a query language for your API and a server-side runtime for executing queries using a type system you define for your data.” It was developed and open-sourced by Meta and is now maintained by a large community of companies and individuals.

GraphQL consists of 2 main parts: -

  1. Schema Definition Language - GraphQL schemas for a service specified using GraphQL SDL (schema definition language), also sometimes referred to as just GraphQL schema language.
  2. Query Language - A query language consists of 3 parts, Query, Mutations and Subscription

We’ll discuss these points in detail later in this article.

GraphQL has a lot of good features, like:

  1. It enables declarative data fetching and provides a single endpoint where a client can specify exactly what’s needed, no more over-fetching of information.
  2. It provides validation and type checking out of the box, you can validate a query within the GraphQL strongly typed system before execution.
  3. It keeps API documentation in sync with API changes. This benefits developers, since they must spend less time documenting an API.
  4. GraphQL removes the need for versioning by deprecating APIs on a field level. Old fields can be later removed from the schema without impacting the existing queries.

There are some disadvantages also: -

  1. GraphQL requires heavier tooling support, both on the client and server sides. This requires a sizable upfront investment. It is not a suitable alternative for very simple use cases of API.
  2. GrpahQL has a single point of entry and uses HTTP POST by default. This prevents the full use of client-side HTTP caching and makes it a non-trivial task to implement caching.

GraphQL Schema

Schema is mandatory in GraphQL service. The GraphQL Schema defines how data is requested and returned from the server and is controlled by GraphQL SDL. Let’s try to understand some of the most important concepts with one sample schema: -

# root Query Type
type Query {
    fetchBooks: [Book]
}

# Book type
type Book {
    id : ID
    name : String
    author: String
    ratings: [Rating]
}

# Rating type
type Rating {
    id: ID
    rating: Int
    comment: String
    user: String
}
Enter fullscreen mode Exit fullscreen mode

Object Types – Object types are specific to GraphQL service, and are defined with the type keyword. They define the type name and the fields under that type. Each field in an object type can be resolved to either scaler types or other object types, e.g., type Book has scaler fields of type String and another object field of type Rating.

Built-In Scaler Types - There are 5 built-in scalar types in GraphQL: Int, Float, String, Boolean, and ID. The ID type resolves to a string but expects a unique value.

Type Modifiers - Modifiers can be used on the type that a field resolves to by using characters like […], e.g. root Query has type modifier [Book], it represents a nullable list of non-nullable string values. The entire value can be null, or specific list elements can be null.

Operations - A GraphQL service can support the following operations: -

  1. Queries: Queries represent READ operations.
  2. Mutation: Mutation comprises WRITE then READ operation.
  3. Subscription: A subscription is used for continuous READ (e.g. over WebSocket).

Getting started

In this article, you’re going to build a book catalog service using Spring Boot GraphQL. This service will support a single query “fetchBooks” to return the top 5 books, authors, and ratings of all times.

We are using Spring for GraphQL to build this service. It is built on GraphQL Java and supports GraphQL request handling over HTTP and WebSocket. GraphQL specification is not tied to any transport layer protocol. I am using GraphQL over HTTP specification to build this API.

Before diving into code, let’s spend some time understanding Spring GraphQL. It has 3 main components, transport, GraphQL Java engine and data fetchers.

Image description

Transport - GraphQL Java doesn’t provide any transport by default. You can use any transport mechanism provided by the Spring framework e.g. Spring MVC, Spring WebFlux, and WebSocket etc. These handlers tunnel all requests GraphQL Java Engine.

GraphQL Java Engine – It has support to bootstrap service from scratch and context propagation from the web layer to the data layer. Exceptions are also handled at this layer.

Data Fetchers – It provides annotated controllers (@Controller), query Domain Specific Language (DSL) and repositories

Service Implementation steps

Step 1: Create a Spring Boot project with dependencies.

You can use spring initializer to create an empty spring boot project with the below dependencies: -

Image description

  • spring-boot-starter-graphql – main dependency
  • spring-boot-starter-web – add this dependency for building the transport layer

Step 2: Create a schema file for our books catalog service.

type Query {
    fetchBooks: [Book]
}

type Book {
    id : ID
    name : String
    author: String
    ratings: [Rating]
}

type Rating {
    id: ID
    rating: Int
    comment: String
    user: String
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a data fetcher.

Data fetcher is a callback function, and it fetches data to include the result of a query. When an incoming GraphQL query is received, the library will call the registered DataFetcher for query. Every query must have an associated DataFetcher, e.g., we’ll create a data fetcher for the “fetchBooks” query in our schema defined in step 2.

Step 4: Type Wiring and RunTime wiring

GraphQL Java uses RuntimeWiring builder to register data fetchers, type resolvers, and more. We’ll create RuntimeWiringConfigurer beans in our Spring config to get access to the RuntimeWiring.Builder. Below code snippet shows data fetcher for “fetchBooks” query and it’s linking with RuntimeWiring builder.

@Configuration
public class GraphQLServiceConfiguration {

    @Bean
    public RuntimeWiringConfigurer runtimeWiringConfigurer(BooksCatalogService bookCatalogService) {
        return builder -> {
            builder.type(
                    "Query",
                    wiring ->
                            wiring
                                    .dataFetcher("fetchBooks", environment -> bookCatalogService.fetchBooks()));
            builder.type(
                    "Book",
                    wiring ->
                            wiring.dataFetcher("ratings", env -> bookCatalogService.fetchRatings(env.getSource())));
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

In the above code, Data Fetcher for field fetchBooks fetches all books and rating by calling books catalog service’s methods fetchBooks() and fetchRatings().

Step 5: Running and Testing

You can start the GraphQL service from IDE by running the main method of BooksCatalogServiceApplication class

Image description

You can use Insomnia client to test your API.
POST : http://localhost:8080/graphql

Image description

You can also use GraphiQL editor in the browser using the link http://localhost:8080/graphiql?path=/graphql.

Image description

To enable GraphiQL editor, you must set spring.graphql.graphiql.enabled=true in application.properties.

The working code example of this article is listed on GitHub. To run the example, clone the repository and import books-catalog-service as a project in your favorite IDE as a Maven project.

Top comments (0)