Data management wıth Relay and GraphQL

Michał Zdunek 

Flux architecture

GraphQL queries

{
  user {
    firstName,
    lastName,
    posts {
      title,
      content
    }
  }
}
{
  "user" {
    "firstName": "Michal",
    "lastName": "Zdunek",
    "posts": [
      {
        "title": "My First Post",
        "content": "Hello"
      },
      {
        "title": "My Second Post",
        "content": "Bye"
      }        
    ]
  }
}

Field arguments

{
  user(id: 2) {
    firstName,
    lastName,
    posts(limit: 1, orderby: DATE) {
      title,
      content
    }
  }
}
{
  "user" {
    "firstName": "Jan",
    "lastName": "Kowalski",
    "posts": [
      {
        "title": "My First Post",
        "content": "Hello"
      }
    ]
  }
}

Fragments

{
  user1: user(id: 1) {
    ...userInfo
  },
  user2: user(id: 2) {
    ...userInfo
  }
}

fragment userInfo on User {
  firstName,
  lastName
}
{
  "user1": {
    "firstName": "Michal",
    "lastName": "Zdunek",
  },
  "user2": {
    "firstName": "Jan",
    "lastName": "Kowalski",
  }
}

Mutations

mutation {
  createUser(
    firstName: "Adam",
    lastName: "Nowak",
  ) {
    id
    firstName
    lastName
  }
}
{
  "createUser": {
    "id": 3,
    "firstName": "Adam",
    "lastName": "Nowak"
  }
}

Type system

type Query {
  user(id: Int): User
}

type User {
  id: Int
  firstName: String
  lastName: String
  posts(limit: Int, orderby: PostOrderEnum): [Post]
}

enum PostOrderEnum {
  DATE,
  TITLE
}

type Post {
  title: String
  content: String
}

Defining queries

const Query = new GraphQLObjectType({
  name: 'Schema',
  description: 'Root of the schema',
  fields: () => ({
    user: {
      type: UserType,
      args: { id: {type: GraphQLInt} },
      resolve: (root, args) => UserService.getUser(args.id)
    }
  })
});

const Schema = new GraphQLSchema({
  query: Query
});

Defining types

const UserType = new GraphQLObjectType({
  name: "User",
  description: "This represent a User",
  fields: () => ({
    _id: {type: new GraphQLNonNull(GraphQLInt)},
    firstName: {type: GraphQLString},
    lastName: {type: GraphQLString},
    posts: {
      type: new GraphQLList(PostType),
      resolve: (user) => PostService.getPosts(user)
    }
  })
});

Defining mutations

const Mutation = new GraphQLObjectType({
  name: "Mutations",
  description: "Mutations of our schema",
  fields: () => ({
    createUser: {
      type: UserType,
      args: {
        firstName: {type: new GraphQLNonNull(GraphQLString)},
        lastName: {type: new GraphQLNonNull(GraphQLString)}
      },
      resolve: (root, args) => UserService.createUser(args)
    }
  })
});

const Schema = new GraphQLSchema({
  query: Query,
  mutation: Mutation
});

Defining mutations

const Mutation = new GraphQLObjectType({
  name: "Mutations",
  description: "Mutations of our schema",
  fields: () => ({
    createUser: {
      type: UserType,
      args: {
        firstName: {type: new GraphQLNonNull(GraphQLString)},
        lastName: {type: new GraphQLNonNull(GraphQLString)}
      },
      resolve: (root, args) => UserService.createUser(args)
    }
  })
});

const Schema = new GraphQLSchema({
  query: Query,
  mutation: Mutation
});

Why use GraphQL?

  • Less coupling between the server and the client
  • With REST, adding a new feature requires a new endpoint
  • With GraphQL, the client simply declares its needs
  • The worst case - we enhance the type declarations on the server

Relay containers

class User extends React.Component {
  render() {
    var {firstName, lastName} = this.props.user;
    return (
      <div>{firstName} {lastName}</div>
    );
  }
}

User = Relay.createContainer(User , {
  fragments: {
    user: () => Relay.QL`
      fragment on User {
        firstName,
        lastName,
      }
    `,
  },
});

Relay - composition

class UsersList extends React.Component {
  render() {
    return <div>
      {this.props.store.users.map(
        user => <User user={user} />
      )}
    </div>;
  }
}

UsersList = Relay.createContainer(UsersList, {
  fragments: {
    store: () => Relay.QL`
      fragment on Store {
        users { ${User.getFragment('user')} },
      }
    `,
  },
});

Relay root container

var usersRoute = {
  queries: {
    store: (Component) => Relay.QL`
      query StoreQuery {
        store { ${Component.getFragment('store')} },
      }
    `,
  },
  name: 'UsersRoute',
};

ReactDOM.render(
  <Relay.RootContainer
    Component={UsersList}
    route={usersRoute}
  />,
  document.getElementById('app')
);

That's all 

  • facebook.github.io/relay
  • graphql.org
Made with Slides.com