Unleashing the power of GraphQL and React

  slides.com/gerardsans | @gerardsans

Google Developer Expert

Master of Ceremonies

Blogger

Trainer

Community Leader

850

1K

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

GitHub announces GraphQL API

New GraphQL website

First GraphQL Summit

GraphQL First

 

2017

Apollo Client 1.0

GraphQL Europe

Launchpad

GraphQL Explore

www.graphql.com

graphql.org

Apollo Optics

launchpad.graphql.com

Implementations

Query Language


// GET '/graphql'
{
 user(name: "gsans") {
  twitter
 }
}

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

GraphQL Server

source: blog

Who is using it?

Solution Architecture

demo

GraphQL Schema

Type System

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

Schema Syntax

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

Schema (1/2)

schema { 
  query: Query,  
  mutation: Mutation 
}

type Query {
  allQuestions(skip: Int, take: Int): [Question!]!
}

type Question {  
  id: ID!
  body: String!
}

Schema (2/2)

schema { 
  query: Query,  
  mutation: Mutation 
}

type Mutation {
  createQuestion(body: String!): Question
}

GraphiQL

demo

Apollo Client

GraphQL Server

source: blog

Dependencies

Setup

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

const networkInterface = createNetworkInterface({
  uri: 'https://api.graph.cool',
  dataIdFromObject: record => record.id, // will be used by caching
})
export const client = new ApolloClient({ networkInterface })

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}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
)

Main APIs

  • query
  • mutate
  • updateQueries (reducer)

query

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

const withQuestions = graphql(
  gql`query questions {
    allQuestion {
      id body
    }
  }`, {
    props: ({ ownProps, data }) => {
      if (data.loading) return { userLoading: true }
      if (data.error) return { hasErrors: true }
      return {
        list: data.allQuestions,
      }
    }
  })

mutate

// App.js
const withAddQuestion = graphql(
  gql`mutation addQuestion($body: String!) {
    createQuestion(body: $body) { 
      id body
    }
  }`,
  {
    props: ({ ownProps, mutate }) => ({
      addQuestion(text) {
        return mutate({
          variables: { body: text },
          updateQueries: {
            todos: (state, { mutationResult }) => {
              return {
                allQuestions: [...state.allQuestions, 
                  mutationResult.data.createQuestion
                ],
              }
         ...

Subscriptions

GraphQL Server

source: blog

Dependencies

Setup

// client.ts
import { SubscriptionClient, addGraphQLSubscriptions } from 'subscriptions-transport-ws'

const wsClient = new SubscriptionClient('wss://subscriptions.graph.cool/v1', {
  reconnect: true,
})

const networkInterface = ...

const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
  networkInterface,
  wsClient
)

export const client = new ApolloClient({
  networkInterface: networkInterfaceWithSubscriptions,
})

Subscription Schema

schema { 
  query: Query,  
  mutation: Mutation,
  subscription: Subscription 
}
type Question { 
  id: ID! 
  body: String! 
}

type Subscription {
  Question(filter: {
    mutation_in: [CREATED]
  }) {
    node {
      id 
      body 
    }
  }
}

Subscribe

// QuestionList.js
const withSubscription = graphql(QUESTIONS_QUERY,
  {
    props: ({ data: { subscribeToMore } }) => ({
      subscribeToNewQuestions() {
        return subscribeToMore({
          document: QUESTIONS_SUBSCRIPTION,
          updateQuery: (state, { subscriptionData }) => {
            const newQuestion = subscriptionData.data.Question.node
            if (!isDuplicate(newQuestion.id, state.allQuestions)) {
              return update(state, {
                allQuestions: {
                  $push: [newQuestion],
                },
              })
            }
          },
        })
      },
    }),
  },
)

Why use GraphQL?

Some reasons

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

Thanks!

Дякую