Flux to GraphQL
Turadg Aleahmad, Remind
@turadg, @RemindEng
● My company is awesome
● GraphQL, what and why
● How to transition
● Tips and gotchas
Outline
Working to connect every teacher, student and parent
In a study, text-message alerts to parents reduced course failures by 39% and
increased class attendance by 17%.
Over 20 million actively use Remind every month (70% of US public schools)
Over 3.6 billion messages delivered on Remind in 2016
Now: Engineering Manager on Engagement team at Remind
N-1 Led our Web platform and Client Infra team
N-2 Started React at Coursera
N-3 Academia
Turadg Aleahmad
Web team
GraphQL
A query language for your API
Requests
POST a query
Get back JSON
Schema
● Over-fetching for 5yr backwards compatibility
● Client-server misunderstandings (nullability, enums, Swagger lies, etc)
● Under-fetching (without getting a backend dev)
● Ad-hoc batching (“graph” queries in REST)
● Rails API monolith hard to break apart
Problems we faced
● Every fetch declares exactly what it needs
● Schema is fully typed and enforced
● Client can batch whatever it likes
● Nested data parsing is well specified
● Lightweight graph resolver service abstracts away all the actual services
Why we adopted GraphQL
Apollo
● Developed by dedicated company
● Optimized for ease of use
● Builds on Redux
● Available now and trustable migration
path
● Will keep stealing from Relay
Choosing a stack
Relay
Used by Facebook
Optimized for performance
Heavier to adopt
Relay 1.0 was going to be replaced by
something very different, with no timeline
(Haven’t looked yet at Relay Modern)
How to transition (n=1)
Started as fast rewrite of an Angular app into React with vanilla Flux pattern.
(Summer 2015)
Backbone, with a store for almost every type. CurrentUser, GroupStore, …
No libraries, just a pattern. No constraints.
Lots of actions that were also blocking promises (shortcut).
Starting point
Had two data access patterns for components:
1. Store updates
2. Promise resolution
Add:
3. Apollo client
…without breaking the other two.
Goal
1.GraphQL server
2.Isolated GraphQL component
3.GraphQL in legacy actions
4.Component queries updating legacy stores
Stages
GraphQL server
Isolated GraphQL component
Test out developer experience and operations
Chose a single form field to test read/write
Low traffic off in the settings page
Used react-apollo abstraction to contain entirely in component
Want all our existing data access to resolved by GraphQL
Had to maintain contract of the actions (Flux and promises)
But also update the Apollo state
GraphQL in legacy actions
Component queries updating legacy stores
Actions were now updating stores and Apollo
Pure GraphQL requests had to manually update stores (localUpdate)
We wanted a way to have legacy stores update when any relevant data came in
by GraphQL
watchQuery fires when any data underlying the query changes
Some REST endpoints we haven’t migrated to GraphQL server yet
Authed User object tricky to move. For push data, no other option.
We don’t want to fetch redundantly so we bring that data into Apollo
Have to match the response structure for the query, including __typename
Adapting legacy data into Apollo
Tips and Gotchas
As components declare what they need, you need to track what you already
have.
dataIdFromObject is the cache key in Apollo’s part of the Redux store.
We ended up writing a lint rule to ensure that the key data is always queried
https://github.com/apollographql/eslint-plugin-graphql/pull/50
Cache keys
HTTP response headers
GraphQL responds 200 if the resolver returns.
The resolver can gather a lot of errors.
Further complicated by network-level query batching.
Have to write logic for what you used to handle by HTTP error codes.
Mobile clients in the wild will continue to require REST
Don’t want to have multiple paths
We created middleware for REST on top of GraphQL
https://github.com/remind101/rest-graphql
REST client compatibility
● Great with Apollo client
● Just rehydrate the Redux store
● All data needs are declared in visual components
● For security, make sure every request gets a fresh client instance
● Also make sure that instance does not have query batching (CPU leak)
Server rendering
● Adopt in small steps
● Plan far ahead
● Get your schema right
● Be creative
Parting thoughts

React Flux to GraphQL

  • 1.
    Flux to GraphQL TuradgAleahmad, Remind @turadg, @RemindEng
  • 2.
    ● My companyis awesome ● GraphQL, what and why ● How to transition ● Tips and gotchas Outline
  • 3.
    Working to connectevery teacher, student and parent In a study, text-message alerts to parents reduced course failures by 39% and increased class attendance by 17%. Over 20 million actively use Remind every month (70% of US public schools) Over 3.6 billion messages delivered on Remind in 2016
  • 4.
    Now: Engineering Manageron Engagement team at Remind N-1 Led our Web platform and Client Infra team N-2 Started React at Coursera N-3 Academia Turadg Aleahmad
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
    ● Over-fetching for5yr backwards compatibility ● Client-server misunderstandings (nullability, enums, Swagger lies, etc) ● Under-fetching (without getting a backend dev) ● Ad-hoc batching (“graph” queries in REST) ● Rails API monolith hard to break apart Problems we faced
  • 10.
    ● Every fetchdeclares exactly what it needs ● Schema is fully typed and enforced ● Client can batch whatever it likes ● Nested data parsing is well specified ● Lightweight graph resolver service abstracts away all the actual services Why we adopted GraphQL
  • 11.
    Apollo ● Developed bydedicated company ● Optimized for ease of use ● Builds on Redux ● Available now and trustable migration path ● Will keep stealing from Relay Choosing a stack Relay Used by Facebook Optimized for performance Heavier to adopt Relay 1.0 was going to be replaced by something very different, with no timeline (Haven’t looked yet at Relay Modern)
  • 13.
  • 14.
    Started as fastrewrite of an Angular app into React with vanilla Flux pattern. (Summer 2015) Backbone, with a store for almost every type. CurrentUser, GroupStore, … No libraries, just a pattern. No constraints. Lots of actions that were also blocking promises (shortcut). Starting point
  • 15.
    Had two dataaccess patterns for components: 1. Store updates 2. Promise resolution Add: 3. Apollo client …without breaking the other two. Goal
  • 16.
    1.GraphQL server 2.Isolated GraphQLcomponent 3.GraphQL in legacy actions 4.Component queries updating legacy stores Stages
  • 17.
  • 18.
    Isolated GraphQL component Testout developer experience and operations Chose a single form field to test read/write Low traffic off in the settings page Used react-apollo abstraction to contain entirely in component
  • 21.
    Want all ourexisting data access to resolved by GraphQL Had to maintain contract of the actions (Flux and promises) But also update the Apollo state GraphQL in legacy actions
  • 24.
    Component queries updatinglegacy stores Actions were now updating stores and Apollo Pure GraphQL requests had to manually update stores (localUpdate) We wanted a way to have legacy stores update when any relevant data came in by GraphQL watchQuery fires when any data underlying the query changes
  • 26.
    Some REST endpointswe haven’t migrated to GraphQL server yet Authed User object tricky to move. For push data, no other option. We don’t want to fetch redundantly so we bring that data into Apollo Have to match the response structure for the query, including __typename Adapting legacy data into Apollo
  • 28.
  • 29.
    As components declarewhat they need, you need to track what you already have. dataIdFromObject is the cache key in Apollo’s part of the Redux store. We ended up writing a lint rule to ensure that the key data is always queried https://github.com/apollographql/eslint-plugin-graphql/pull/50 Cache keys
  • 31.
    HTTP response headers GraphQLresponds 200 if the resolver returns. The resolver can gather a lot of errors. Further complicated by network-level query batching. Have to write logic for what you used to handle by HTTP error codes.
  • 34.
    Mobile clients inthe wild will continue to require REST Don’t want to have multiple paths We created middleware for REST on top of GraphQL https://github.com/remind101/rest-graphql REST client compatibility
  • 35.
    ● Great withApollo client ● Just rehydrate the Redux store ● All data needs are declared in visual components ● For security, make sure every request gets a fresh client instance ● Also make sure that instance does not have query batching (CPU leak) Server rendering
  • 36.
    ● Adopt insmall steps ● Plan far ahead ● Get your schema right ● Be creative Parting thoughts