Relay Explained*

 

George Lee

github.com/keokilee

twitter.com/keokilee

* Relay is Hard

What is Relay?

A Javascript framework for building data-driven React applications

https://facebook.github.io/relay/

https://facebook.github.io/react/blog/2015/03/19/building-the-facebook-news-feed-with-relay.html

http://www.bebetterdeveloper.com/coding/getting-started-react-redux.html

Relay and Flux/Redux can be used together

The Frontend Story

Relay's Expectations

  • Your server uses GraphQL
  • Component hierarchy matches data hierarchy

Viewer (Logged in user)

News Feed

 

pagination info

Posts

 

id

text

avatar

Author

query {
    viewer {
        name,
        news_feed {
            pageInfo {
                hasNextPage,
                hasPreviousPage
            },
            edges {
                cursor,
                node {
                    id,
                    text,
                    avatar,
                    author {
                        name
                    }
                }
            }
        }
    }
}

Relay Gets What's Needed

Posts may have timestamps, but if no components in the tree need it, Relay won't fetch it.

 

Relay also maintains a cache. If we need the timestamps on another page, Relay will only fetch the new fields.

https://gist.github.com/keokilee/fbf674c3ec6f634b0e5861bc716a7910

Why isn't everyone using Relay?

Relay can work with a basic schema

 

But if you want to unleash it's full potential ...

Think about your data model differently

User
name
user_posts
UserPosts
user
posts
Post
text
avatar
author

Note: Your data may actually be structured like this

User

Post

Post

Post

User

User

Circles are "nodes"

Arrows are "edges"

Relay Jargon

Nodes, connections, and edges

Relay Node

A node is a top level entity in your application. GraphQL types that are nodes implement an interface

  • The id field is a global id that encodes the type of object and the database id of the object (Relay uses this to cache on the frontend)
  • Given the global id, the node interface can get the type and object id and query the database.
  • Given the object, the node interface knows what the type of the object is
var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    switch (type) {
        case 'User':
            return User.get(id)
        case 'Post':
            return Post.get(id)
    }
  },
  (obj) => {
    return obj.name ? UserType : PostType
  }
)

const UserType = new GraphQLObjectType({
    // ...
    // Instead of second arg above, each type can implement isTypeOf
    isTypeOf: (obj) => !!obj.name
    interfaces: [nodeInterface]
})


const PostType = new GraphQLObjectType({
    // ...
    interfaces: [nodeInterface]
})

Brief Detour: Pagination

Standard Pagination

  • Page numbers and page sizes
  • Used in many bulletin boards and forums
  • What about real time updates?

Cursor Based Pagination

  • A page size and a cursor id
  • Forward Pagination: "First <page size> after <cursor id>"
  • Backward Pagination: "Last <page size> before <cursor id>"

Relay Connection

The connection type represents a one-to-many relationship in Relay. Connections implement the following:

 

  • It supports pagination arguments (first, after, last, before)
  • The resolver fetches the data and returns a list of edges along with pagination info

Relay Edge

Edges are the relation between two objects. An edge implements the following interface:

 

  • Edge has a field called "cursor" that the Connection can use in the "after" or "before" arguments
  • Edge has a Node

It's Just Pagination

The graphql-relay-js library has helpers for generating a Connection between one entity and another. Other GraphQL implementations have similar helpers.

 

https://github.com/graphql/graphql-relay-js#connections

Relay-Compliant Schema

The "Viewer"

"Viewer" is the entry point for the components in your app. The name is not special (it could be anything) and there can be more than one.

 

One restriction: "Viewer" may only take 0 or 1 argument. You'll get an error if you try to access it from Relay otherwise.

Node

"Node" takes one argument, an id (which is a global Relay id). The server takes that id and returns the matching object that implements the node interface. 

 

This is the "nodeField" that was mentioned in the previous section.

Nodes (optional)

Behaves like node, but takes an array of ids and returns the matching objects.

Relay

By George Lee

Relay

  • 1,197