Skip to content

add_relay_connection

etienne-sf edited this page Sep 15, 2025 · 3 revisions

Breaking change in v3.0

This page describes the behaviour, starting from the 3.0 version. This capability existed also in the 1.x (starting from the 1.11) and 2.X versions of the plugin. But the behaviour changed in 3.0:

Adding the Relay Connection capability into a GraphQL Schema (version v3.0 and after)

A note about the Relay Connection capability

The Relay Connection is the standard GraphQL way to navigate through big sets of data, when retrieving a complete list of objects is a non-sense (for instance all the customers of a company, all books of a library...). The Relay Connection allow to navigate in the big set of data, page per page.

This is defined in the Relay specification: you can check the Relay GraphQL server specification or the Relay connection specification.

TODO : check this blog page, as the Animal sample proposal is slightly more strict than the spec. TODO : if this impacts the implementation, update the doc below (especially what's generated)

The implementation of the Relay Connection in the GraphQL plugin has been enhanced in the 3.0 version, to properly implement the GraphQL 2021 specification: this specification added the capability of an interface to implement another interface. This is explained in this page: Intermediate Interfaces & Generic Utility Types in GraphQL. The sample used in this page is used in the samples of the plugin's maven and gradle project, to execute integration tests of the implementation.

Usage of Relay Connection in the GraphQL plugin

TODO : finish below

Every goal/task of the GraphQL plugin has these plugin parameters:

  • addRelayConnections tells the plugin to activate this capability. The default value is false. Setting it to true activates the plugin capability.
  • targetFolder is the folder where the updated GraphQL schema is generated. Its default value ${project.build.directory}/generated-resources/graphql-maven-plugin_generate-relay-schema
  • targetSchemaFileName is the name of the file that will contain the generated schema. The default filename is generated_schema.graphqls

TODO : correct and complete the below goals/tasks The addRelayConnections parameter may be used in these goals/tasks of the plugin:

  • generateClientCode: this allows to generate a schema, with its XxxConnection and XxxEdge classes, the Node interface, the PageInfo type... The you can use the generated GraphQL schema in any tool you want.
  • generateClientCode: this allows to have a GraphQL client that is able to call a server with these XxxConnection and XxxEdge classes, Node interface, PageInfo type...
  • generateServerCode: this allows to create a GraphQL server that manages these XxxConnection and XxxEdge classes, Node interface, PageInfo type...
  • graphql This deprecated goal/task should be avoided. But if you use it, it can use the addRelayConnections parameter as the generateClientCode and generateServerCode tasks/goals.

The usage of the Relay Connection implementation in the GraphQL plugin is based on the @RelayConnection directive. To use it, you must declared it in your GraphQL schema like this:

directive @RelayConnection on OBJECT | INTERFACE 

Once the addRelayConnections is set to true:

  • You must declare the @RelayConnection directive, as indicated here above
  • You apply the @RelayConnection directive to:
    • All types the must be accessed though the relay connection
    • Interfaces for which each implementing type must be accessed though the relay connection
    • All types and interfaces that implement these interfaces

Then, the plugin:

  • Generates the GraphQL schema that includes the Relay Connection classes and interfaces
    • TODO check that this schema is also generated when in client mode.
    • TODO check that the generateSchema is not necessary, when in server mode.
      • But it is still necessary to check that the schema generated by the generateSchema is valid (in the forum server sample),
  • Declares the standard Relay Connection type and interfaces:
    • The PageInfo type
    • The Node, Edge and Connection interfaces
  • For each interface marked by the @RelayConnection directive:
    • Checks that each interface and each type that implements this interface is also marked by the @RelayConnection directive. If not, the plugin fails.
    • Creates the XxxEdge interface (which implements the Edge interface)
    • Creates the XxxConnection interface (which implements the Connection interface)
    • Extend the Xxx interface, so that it implements the Node interface (and add
  • For each type marked by the @RelayConnection directive:
    • Creates the XxxEdge interface (which implements the Edge interface)
    • Creates the XxxConnection interface (which implements the Connection interface)
    • Extend the Xxx interface, so that it implements the Node interface (and add
  • For each field which type is a list of a type or an interface that is marked by the @RelayConnection directive:
    • Replace the field's type (e.g. [Xxx]) by XxxConnection
  • When in the server mode, the relevant DataFetchersDelegate are added. Please have look at the server page for more information on DataFetchersDelegate. Your code must implement these DataFetchersDelegate:
    • The DataFetchersDelegateNode data fetchers delegate
    • The DataFetchersDelegateXxxxConnection data fetchers delegates, for each interface and type marked by the @RelayConnection directive
    • The DataFetchersDelegateXxxxEdge data fetchers delegates, for each interface and type marked by the @RelayConnection directive

Notes :

  • For an Xxx type marked by the @RelayConnection directive:
    • If a field's type is Xxx (not a list), then it remains unchanged
    • If a field's type is [[Xxx]], only the the first level is replaced by a XxxConnection, so the field's type generated by the plugin is [XxxConnection]. The same logic applies if the list has more than two levels. TODO: test with a two-levels list (including DataFetcher and query execution)

TODO : how works the generated DAtaFetchersDelegate. IS their a defaulty implementtation ? This must be documented

Details of the plugin's behaviour

When the addRelayConnections plugin parameter is set to true, the plugin reads the GraphQL schema file(s), and enriches the GraphQL schema with the interfaces and types needed to respect the Relay Connection specification. The entry point for that is the @RelayConnection directive. It is specific to this plugin. It can be added to any type or interface. Here are

What does the plugin, to manage the Relay Connection capability

Then the @RelayConnection directive may be added to every field that should be used through a Relay connection. That is: the field's type, whether it's a list or not, is replaced by the relevant XxxConnection type.

For instance the query:

query {
  ...  
  allHumans(criteria: String): [Human] @RelayConnection,
  ...
}

is replaced by:

query {
  ...  
  allHumans(criteria: String): HumanConnection! @RelayConnection,
  ...
}
type HumanConnection {
	edges: [HumanEdge] 
	pageInfo: PageInfo! 
}

type HumanEdge {
	node: Human 
	cursor: String! 
}

type PageInfo {
	hasNextPage: Boolean! 
	hasPreviousPage: Boolean! 
	startCursor: String! 
	endCursor: String! 
}

interface Node {
	id: ID! 
}

# The Character interface is marked as implementing the Node interface
type Human implements Node { 
  ...
} 

And the field:

Human {
   ...
   friends: Character @RelayConnection,
   ...
}

is replaced by:

Human {
   ...
   friends: CharacterConnection! @RelayConnection,
   ...
}

interface CharacterConnection {
	edges: [CharacterEdge] 
	pageInfo: PageInfo! 
}

interface CharacterEdge {
	node: Character 
	cursor: String! 
}


type PageInfo {
	hasNextPage: Boolean! 
	hasPreviousPage: Boolean! 
	startCursor: String! 
	endCursor: String! 
}

interface Node {
	id: ID! 
}

# The Character interface is marked as implementing the Node interface
interface Character implements Node { 
  ...
} 

Please note that:

  • The field's type marked with the @RelayConnection may be either a type or an interface. As it's a field's type, it may not be an input type.
  • The field's type marked with the @RelayConnection MUST contain an id field, of type ID. Otherwise, an error is thrown at code generation time.
  • If the @RelayConnection directive is set on a field of an interface, it will be applied to this interface's field, and to this field for all type that implements this interface.
    • In this later case, the directive should also be set to this field, for all the implementing type. If not, a warning is generated.
  • If the @RelayConnection is not set on a field of an interface, but is set in the same field, for one type that implements this interface, then an error is generated.
  • For each type marked at least once, with the @RelayConnection directive (the Human type, and the Character interface, here above), the relevant XxxConnection and XxxEdge type ares added to the in-memory schema.
  • The Node interface is added as being implemented by each type marked at least once, with the @RelayConnection directive. For instance, in the two samples above, the Human type and the Character interface are marked as implementing the Node interface.
  • In server mode, the relevant DataFetchersDelegate are added. Please have look at the server page for more information on this. So your code has to implement:
    • The DataFetchersDelegateNode data fetcher delegate
    • The DataFetchersDelegateXxxxConnection data fetcher delegates, for each field's type or field's interface marked with the @RelayConnection directive
    • The DataFetchersDelegateXxxxEdge data fetcher delegates, for each field's type or field's interface marked with the @RelayConnection directive

Important note about the GraphQL schema for the server mode

The generated code is based on the graphql-java engine. This engine, when it starts the GraphQL server, needs to have access to the GraphQL schema. As the plugin updates the given GraphQL schema, based on the applied @RelayConnection directives, it also generates a GraphQL schema file.

This generated GraphQL schema file is named generated_schema.graphqls.

TODO : Check the below paragraph As a consequence, the provided must either have another name, or be stored in another place than the src/main/resources folder. To do this, you'll have to use the schemaFileFolder plugin parameter.

Which tasks are executed by the plugin?

To sum-up, if addRelayConnections plugin parameter is set to true, the plugin will:

  • Check that the @RelayConnection directive definition exists in the GraphQL schema, and is compliant with the above definition
  • Add the Node interface in the GraphQL schema (if not already defined).
    • If this interface is already defined in the given schema, but is not compliant with the relay specification, then an error is thrown.
  • Add the PageInfo type in the GraphQL schema (if not already defined).
    • If this type is already defined in the given schema, but is not compliant with the relay specification, then an error is thrown.
  • All the Edge and Connection type in the GraphQL schema, for each attribute's type that is marked by the @RelayConnection directive.
Clone this wiki locally