Spring for GraphQL: @SchemaMapping and @QueryMapping

Pankaj Kumar
4 min readJul 29, 2022

--

In the last article Getting started with Spring Boot GraphQL service, we discussed features of GraphQL and its implementation in Spring for GraphQL using low-level APIs of GraphQL Java.

While low-level GraphQL Java implementation is fine for understanding the concept, you’ll mostly use higher-level abstraction provided by Spring.

In this article, we will discuss the @Controller, @QueryMapping, and @SchemaMapping of Spring for GraphQL.

Here, we’ll use the same book catalog GraphQL API, described in an earlier article (also shown below).

GraphQL query

Let’s get started!

Controller

Like REST API, Spring Boot offers @Controller annotation to implement GraphQL APIs. All you need to do is to annotate your controller class with @Controller annotation and define either @QueryMapping or @SchemaMapping annotation on the handler method.

Spring detects @Controller beans and registers their annotated handler methods ( @QueryMapping or @SchemaMapping) as DataFetcher s (also known as a resolver).

A resolver/DataFetcher is a function that’s responsible for populating the data for a single field in your GraphQL schema.

SchemaMapping Annotation

The @SchemaMapping annotation maps a handler method to a field in the GraphQL schema as DataFetcher. All you need to do is to define the typeName and, optionally, the field with @SchemaMapping.

Additionally, if you keep the method name as same as the field name then you can omit the field from @SchemaMapping.

What happens if you don’t specify the typeName with @SchemaMapping (as shown below) ?

In this case, Spring can’t figure out which parent-type field books belong to; therefore, it'll throw BeanCreationException, at the application startup, with a helpful error message.

No parentType specified, and a source/parent method argument was also not found: BooksCatalogController#books[0 args]

Similarly, for the field bookById, you can define a data fetcher as:

Here, we have used @Argument annotation to map argument id as @Argument("id") Integer id.

Finally, you can test this by heading over to http://localhost:8080/graphiql?path=/graphql in your browser.

Data Fetcher for the child ‘Type’ field

If you query GraphQL service with the ratings field of Book the response includes "ratings": null.

Why?

If you don’t specify a Data Fetcher for a field the GraphQL Java assigns a default PropertyDataFetcher. Subsequently, at the runtime this PropertyDataFetcher looks for public getRatings() field in the Book POJO (as field ratings belongs to the Book).

To solve this, you can define a Data Fetcher for ratings. As the field ratings belongs to the parent type Book, you need to pass Book in the argument.

While GraphQL Java is executing a query, it calls the appropriate DataFetcher for each field it encounters in the query. If you don't define any DataFetcher it assigns PropertyDataFetcher as default.

And, you can write without specifying the field as:

Also as:

In @SchemaMapping you can also leave out typeName and field attributes, in which case the field name defaults to the method name, while the type name defaults to the simple class name of the source/parent object injected into the method.

QueryMapping annotation

Instead of using @SchemaMapping, you can use @QueryMapping. Effectively, this is a shortcut annotation to bind annotated methods for fields under the Query type.

Moreover, you can skip the name from annotation. In this case, Spring derives the query field from the method name.

Similarly, for the Query field bookById:

You can’t use @QueryMapping for the field ratings as it doesn't belong to the type Query.

Configuration

By default, the Boot starter checks in src/main/resources/graphql for GraphQL schema files with extensions ".graphqls" or ".gqls ". To override this behavior, you can change the following property.

spring.graphql.schema.locations=classpath:graphql/ spring.graphql.schema.fileExtensions=.graphqls, .gqls

Code example

The working code example of this article is listed on GitHub . To run the example, clone the repository, and import graphql-spring-annotation as a project in your favorite IDE as a Gradle project.

Summary

Spring greatly simplifies the development of GraphQL APIs by the way of @Controller annotation. You just need to annotate your Controller classes with @Controller annotation and define either @QueryMapping or @SchemaMapping annotation on the handler method.

Spring detects @Controller beans and registers their annotated handler methods as DataFetcher s (also known as a resolver).

Originally published at https://techdozo.dev on July 29, 2022.

--

--

Pankaj Kumar

Software Architect @ Schlumberger ``` Cloud | Microservices | Programming | Kubernetes | Architecture | Machine Learning | Java | Python ```