-
Notifications
You must be signed in to change notification settings - Fork 50
add_relay_connection
- Breaking change in v3.0
- Adding the Relay Connection capability into a GraphQL Schema (version v3.0 and after)
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:
- With 1.x and 2.x versions, the
@RelayConnection
directive applies to fields. You'll find the documentation for these versions in the page Adding the Relay Connection capability into a GraphQL Schema (1.x and 2.x versions) - Starting with the 3.0 version, , the
@RelayConnection
directive applies to type and interfaces, but no more on fields. You'll find the documentation below, in the page.
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.
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 isfalse
. Setting it totrue
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 isgenerated_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
- Checks that each interface and each type that implements this interface is also marked by the
- 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
- Replace the field's type (e.g.
- 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)
- If a field's type is
TODO : how works the generated DAtaFetchersDelegate. IS their a defaulty implementtation ? This must be documented
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
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
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.
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.
Adding Relay Connection capability to a GraphQL schema
Creating a first app (non spring)
Connect to more than one GraphQL servers
Easily execute GraphQL requests with GraphQL Repositories
Access to an OAuth2 GraphQL server
How to personalize the client app
Howto personalize the generated code
Client migration from 1.x to 2.x
Implement an OAuth2 GraphQL server
Howto personalize the generated code