The amazing GraphQL

slides.com/gerardsans | @gerardsans

Google Developer Expert

Master of Ceremonies

Blogger

GraphQL

GraphQL co-authors

Lee Byron

Nick Schrock

Dan Schafer

GraphQL Timeline

2012

GraphQL created at Facebook

Support Mobile Native Teams

2015

Open sourced

First Specification

GraphQL.js

2016

New GraphQL website

First GraphQL Summit

GraphQL First

graphql.org

graphqlsummit.com

GraphQL Server

source: blog

Implementations

Query Language


// Query
{
 user(name: "gsans") {
  twitter
 }
}

// Result
{
 "user": {
  "twitter": "@gerardsans"
 }
}

GraphQL Server

source: blog

Who is using it?

Solution Architecture

demo

Components Tree

<app>
  <add-todo>
    <input><button>Add todo</button>
  </add-todo>
  <todo-list>
    <ul>
      <todo id="0" completed="false"><li>buy milk</li></todo>
    </ul>
  </todo-list>
  <filters>
    Show: <filter-link><a>All</a><filter-link> ... 
  </filters>
</app>

GraphQL Schema

Type System

  • Scalar Types: Int, Float, String, Boolean, ID 
  • Object Types: Todo
  • Entry points: Query, Mutation, Subscription

Schema Syntax

  • Nullable: String, Todo
  • Non-nullable: String!, Todo!
  • Arrays: [String], [Todo]

Todos Schema (1/2)

schema { 
  query: Query,  
  mutation: Mutation 
}

type Query {
  allTodoes(skip: Int, take: Int): [Todo!]!
}

type Todo {  
  id: ID!
  text: String!
  complete: Boolean!
}

Todos Schema (2/2)

schema { 
  query: Query,  
  mutation: Mutation 
}

type Mutation {
  createTodo(text: String!, complete: Boolean!): Todo
  updateTodo(id: ID!, text: String, complete: Boolean): Todo
}

GraphiQL

demo

Apollo Client

Dependencies

Setup

// client.js
import ApolloClient, { createNetworkInterface } from 'apollo-client'

const networkInterface = createNetworkInterface('https://api.graph.cool')
export const client = new ApolloClient({ networkInterface });

Todo App

// TodoApp.js
class TodoApp extends React.Component {
  render () {
    return (
      <div>
        <AddTodo addTodo={this.props.addTodo} />
        <TodoList
          todos={this.props.todos || []}
          filter={this.props.currentFilter}
          toggleTodo={this.props.toggleTodo}
        />
        <Filters setFilter={this.props.setFilter} 
          filter={this.props.currentFilter} />
      </div>
    )
  }
}

Bootstrap

// app.js
import { ApolloProvider } from 'react-apollo'

let combinedReducer = combineReducers({
  filter, 
  apollo: client.reducer(),
})

const store = compose(
  applyMiddleware(client.middleware())
)(createStore)(combinedReducer)

render(
  <ApolloProvider store={store} client={client}>
    <TodoApp />
  </ApolloProvider>,
  document.getElementById('root')
)

Main APIs

  • query
  • mutate
  • updateQueries (reducer)

query

// TodoApp.js
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

const withTodos = graphql(
  gql`query todos {
    allTodoes {
      id complete text
    }
  }`, {
    props: ({ ownProps, data }) => {
      if (data.loading) return { userLoading: true }
      if (data.error) return { hasErrors: true }
      return {
        todos: data.allTodoes,
      }
    }
  })

mutate

// TodoApp.js
const withAddTodo = graphql(
  gql`mutation addTodo($text: String!) {
    createTodo(text: $text, complete: false) { id }
  }`,
  {
    props: ({ ownProps, mutate }) => ({
      addTodo (text) {
        return mutate({
          variables: { text },
          updateQueries: {
            todos: (state, { mutationResult }) => {
              return {
                allTodoes: [...state.allTodoes, {
                  id: mutationResult.data.createTodo.id,
                  text: text,
                  complete: false,
                }],
              }
         ...

connect

// TodoApp.js
import { connect } from 'react-redux'
const withTodos = graphql(...)
const withAddTodo = graphql(...)
const withToggleTodo = graphql(...)

const TodoAppWithState = connect(
  (state) => ({ currentFilter: state.filter }),
  (dispatch) => ({
    setFilter: (filter) => {
      dispatch({
        type: 'SET_FILTER',
        filter,
      })
    },
  }),
)(TodoApp)

export default withTodos(withAddTodo(withToggleTodo(TodoAppWithState)))

Why use GraphQL?

Some reasons

  • Declarative
  • De-coupled from storage
  • Validated and structured
  • Facilitates Collaboration
  • Super fast

Thanks!