Home

January 12, 2024

New @GraphQLIgnore Annotation: Code-First Schema in Spring

I recently incorporated the spring-graphql library into a project that had been using the graphql-java-annotations library for satisfying the “code-first” approach to GraphQL schema generation.

The problem I faced: how to unify the interfaces defining the schema, with the controllers defining the actual data fatchers executed at runtime?

As an example, a method used to generate the schema using graphql-java-annotations might be:

public interface Foo {

  @GraphQLField
  @GraphQLNonNull Bar bar(@GraphQLName("baz") @GraphQLNonNull String baz);
}

while the method mapped to that field at runtime using spring-graphql might be:

public class FooController {

  @SchemaMapping
  public Bar bar(
      Foo foo,
      GraphQLContext context,
      @Argument String baz) {
    // ...  
  }
}

The schema I was working with was non-trivial, so I ruled out keeping these definitions separate, as it would have quickly become chaotic.

So I experimented with various approaches to making the controllers implement the original interfaces, but ultimately abandoned that approach after realizing it wasn’t possible.

Eventually I merged the interface definitions into the controllers, producing methods like this:

public class FooController {

  @SchemaMapping
  @GraphQLField
  public @GraphQLNonNull Bar bar(
      Foo foo,
      GraphQLContext context,
      @Argument @GraphQLName("baz") @GraphQLNonNull String baz) {
    // ...  
  }
}

New problem: what to do about parameters foo and context?

  • foo is the “source” object on which this controller is operating
  • context is the extra state we have for this particular GraphQL request

If we run graphql-java over this method definition and ask it to produce a schema:

  • foo is a valid schema type, but by including it, any caller of this field will be contractually required to provide a Foo; this is undesirable, as a Foo need only be supplied at runtime by the environment
  • context is not a valid schema type, so graphql-java will abort with an error

Prior to December 2023, there was no way to simply ignore these parameters at schema-generation time. In PR #299 of the graphql-java-annotations library, I added a new annotation @GraphQLIgnore that does just that: ignores any parameter on which it is present. Now we can write:

public class FooController {

  @SchemaMapping
  @GraphQLField
  public @GraphQLNonNull Bar bar(
      @GraphQLIgnore Foo foo,
      @GraphQLIgnore GraphQLContext context,
      @Argument @GraphQLName("baz") @GraphQLNonNull String baz) {
    // ...  
  }
}

The end result is that this single method definition can be used both at compile-time for schema generation and at runtime for execution, without any duplication or extra maintenance burden. This should make the code-first GraphQL development style much more pleasant when using Spring’s GraphQL runtime library.