Relay

Relay requires quite some boilerplate type definitions to be defined. They are all the same apart from type of the node the Relay connection targets. This results in schemas with a lot of duplication, like the following:

type Query {
    users(first: Int, after: String): UserConnection
    organizations(first: Int, after: String): OrganizationConnection
}

type UserConnection {
    edges: [UserEdge]
    pageInfo: PageInfo
}

type UserEdge {
    cursor: String
    node: User
}

type PageInfo {
  hasPreviousPage: Boolean!
  hasNextPage: Boolean!
}

type User {
    id: ID!
    name: String
}

type OrganizationConnection {
    edges: [OrganizationEdge]
    pageInfo: PageInfo
}

type OrganizationEdge {
    cursor: String
    node: Organization
}

type Organization {
    id: ID!
}

Using the Type Definition Factory

In version 5.4 of graphql-java-tools the Type Definition Factory has been introduced. This has been added with this particular use case in mind, but can be used for any type of definition that you’d want to add dynamically instead of defining it statically in the SDL.

To support Relay we have created the RelayConnectionFactory that is enabled by default. It scans the SDL for any fields annotated with the custom directive @connection. For each it will dynamically add the required type definitions to the schema. It also requires the PageInfo type definition.

By using this feature the schema definition shown above can be reduced to:

type Query {
    users(first: Int, after: String): UserConnection @connection(for: "User")
    organizations(first: Int, after: String): OrganizationConnection @connection(for: "Organization")
}

type User {
    id: ID!
    name: String
}

type Organization {
    id: ID!
}

The connection type will be created if absent using the type name specified for the field, e.g. UserConnection and OrganizationConnection in the example above. The edge type will get the same name appended with Edge, e.g. UserConnectionEdge and OrganizationConnectionEdge for this example.

Creating the resolver

In the resolvers the Relay connection provided by graphql-java can be used, for example:

class QueryResolver implements GraphQLQueryResolver {

  public Connection<User> users(int first, String after, DataFetchingEnvironment env) {
    return new SimpleListConnection<>(Collections.singletonList(new User(1L, "Luke"))).get(env);
  }
}