Relay is a JavaScript framework for building data-driven React applications with GraphQL which is developed and used by Facebook.
Relay makes three assumptions about the backend which you have to abide by in order that your GraphQL backend plays well with this framework.
We recommend that you abide to the relay server specifications even if you do not plan to use relay since even Apollo supports these specifications and they are really good guidelines that lead to a better schema design.
Object Identification
The first specification is called Relay Global Object Identification Specification and defines that object identifiers are specified in a standardized way. Moreover, it defines that all identifier is schema unique and that we can refetch any object just by providing that identifier.
In order to support the schema has to provide an interface Node
that looks like following:
interface Node { id: ID!}
Each object that exposes an identifier has to implement Node
and provide the id
field.
Moreover, the Query
type has to expose a field node
that can return a node for an id.
type Query { ... node(id: ID!) : Node ...}
This allows now the client APIs to automatically refetch objects from the server if the client framework wants to update its caches or if it has part of the object in its store and wants to fetch additional fields of an object.
Hot Chocolate makes implementing this very easy. First, we have to declare on our schema that we want to be relay compliant:
ISchema schema = SchemaBuilder.New() .EnableRelaySupport() ... .Create();
This basically sets up a middleware to encode out identifiers to be schema unique, so you do not have to provide schema unique identifiers. Moreover, it will add a Node
interface type and configure the node
field on our query type.
Lastly, we have to declare on our object types that they are nodes and how they can be resolved.
public class MyObjectType : ObjectType<MyObject>{ protected override void Configure(IObjectTypeDescriptor<MyObject> descriptor) { descriptor.AsNode() .IdField(t => t.Id) .NodeResolver((ctx, id) => ctx.Service<IMyRepository>().GetMyObjectAsync(id)); ... }}
On the descriptor we mark the object as a node with AsNode
after that we specify the property that represents our internal identifier, last but not least we specify the node resolver that will fetch the node from the database when it is requested through the node
field on the query type.
There are more variants possible and you can even write custom resolvers and do not have to bind to an explicit property.
Connections
The pagination specification is called Relay Cursor Connections Specification and contains functionality to make manipulating one-to-many relationships easy, using a standardized way of expressing these one-to-many relationships. This standard connection model offers ways of slicing and paginating through the connection.
The relay style pagination is really powerful and with Hot Chocolate it is quite simple to implement.
If your database provider can provide it`s data through IQueryable
then implementing relay pagination is one line of code:
public class QueryType : ObjectType<Query>{ protected override void Configure(IObjectTypeDescriptor<Query> descriptor) { descriptor.Field(t => t.Strings).UsePaging<StringType>(); }}
We have a lot more documentation on pagination here.
Mutations
The last specification is called Relay Input Object Mutations Specification and it describes how mutations should be specified. This is more a design guideline then something we could help you with APIs with.
Nevertheless, with version 9.1 we will try aide this with some convenience: Automatic Relay InputType.
Additional Information
The relay server specifications are also summarized and explained here. Also, if you have further questions head over to our slack channel.