Slide 1

Slide 1 text

GraphQL and Relay

Slide 2

Slide 2 text

@helielson @hyetho @rodrigopr @rodrigoropr

Slide 3

Slide 3 text

Topics - GraphQL What is it? Motivation Spec Implementations How we use it What is coming

Slide 4

Slide 4 text

Definition GraphQL is a query language designed to build client applications by providing an intuitive and flexible syntax for describing their data requirements and interactions.

Slide 5

Slide 5 text

Why invent something new? What about REST and Ad hoc endpoints?

Slide 6

Slide 6 text

REST problems - Multiple round trips to render single views - Receives unnecessary data - Payloads tend to grow over time for all clients

Slide 7

Slide 7 text

- Code duplication - API changes with client need - Hard to scale with multiple clients - Hard to keep backwards compatibility Ad hoc endpoints (view oriented)

Slide 8

Slide 8 text

How we think about data? - Not tables, joins or URIs - But: - Objects - Properties - Relationships - What, not How

Slide 9

Slide 9 text

GraphQL

Slide 10

Slide 10 text

- Product-centric - Hierarchical - Client-specified queries - Strongly-typed Principles:

Slide 11

Slide 11 text

Product-centric

Slide 12

Slide 12 text

Hierarchical

Slide 13

Slide 13 text

{ post(id: 65) { title, votes, author { name, avatar } } } Hierarchical

Slide 14

Slide 14 text

{ post(id: 65) { title, votes, author { name, avatar } } } Hierarchical { "post": { "title": "Post title", "votes": 100, "author" { "name": "Didi", "avatar": "http://x.jpg" } } }

Slide 15

Slide 15 text

Strong-Typing

Slide 16

Slide 16 text

Client-specific Queries

Slide 17

Slide 17 text

Not tied to: - Language - Framework - Database - Protocol

Slide 18

Slide 18 text

Schema - Think as a Graph - Define structure of nodes (properties) - How they are connected

Slide 19

Slide 19 text

Schema User { name: String! email: String! followers: [User] isFriendOf(otherEmail: String!): Boolean }

Slide 20

Slide 20 text

Schema query { post(postId: Int!): Post! user(email: String!): User! me: User }

Slide 21

Slide 21 text

Type System - Interface - Object - Enum - Union - List - Scalars: - String, Int, Boolean

Slide 22

Slide 22 text

Query language { user(email: "[email protected]") { name followers { name } } }

Slide 23

Slide 23 text

query { user(email: "[email protected]") { ...userInfo followers { ...userInfo } } } fragment userInfo on User { name, email lastPosts { ...somePostFrament } }

Slide 24

Slide 24 text

fragment petInfo on Pet { petName, owner { name } … on Dog { noiseVolume: barkVolume } … on Cat { noiseVolume: meowVolume } }

Slide 25

Slide 25 text

Variables query houseTrainedQuery($atOtherHomes: Boolean) { dog { isHousetrained(atOtherHomes: $atOtherHomes) } }

Slide 26

Slide 26 text

Fragment directives fragment maybeFragment on Query @include(if: $condition) { me { name } }

Slide 27

Slide 27 text

Fragment directives query myQuery($someTest: Boolean) { experimentalField @skip(if: $someTest) }

Slide 28

Slide 28 text

Mutation mutation { submitComment(postId: 1, user: "...", content: "") { createdComment { id, url } } }

Slide 29

Slide 29 text

Open to optimizations - Batch - Cache - "DataLoader is the true" http://github.com/facebook/dataloader

Slide 30

Slide 30 text

Network-GraphQL (how we are using) - Unify object definition - Unify loader definition - Helper for thrift-style relationships - Add an extra optimization layer - Auto extract selections from query

Slide 31

Slide 31 text

Network-GraphQL (how we are using) - Define the schema based on jusbrasil-types - Rethinking data structure - english - relationships - building as we need - Based on network Thrift API

Slide 32

Slide 32 text

What's coming next? - Open source movement - Improve data coverage - Provide authorization in schema (acl) - Mutation (done) - Object authorization - Field authorization

Slide 33

Slide 33 text

Questions?

Slide 34

Slide 34 text

Relay

Slide 35

Slide 35 text

Topics - Relay What is it? Motivation Spec Implementation How we use it What is coming

Slide 36

Slide 36 text

Definition A javascript framework for building data-driven react applications

Slide 37

Slide 37 text

Dispatcher View Store Action

Slide 38

Slide 38 text

Dispatcher View Store Action Server

Slide 39

Slide 39 text

Let's make an App !! Will be easy !!!!

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

How to load data from server?

Slide 42

Slide 42 text

Slide 43

Slide 43 text

A lot of trips between server and client /feed # get feed (documents ids) /documents/{id} # get a document /topics/{id} # get a topic Reuse the endpoint

Slide 44

Slide 44 text

A big payload /feed_with_topics_max_tree_documents One custom endpoint that loads everything

Slide 45

Slide 45 text

/feed?topics=true&max_documents=3 Multiple custom endpoints

Slide 46

Slide 46 text

And what about: Pagination? Ordering? Error handling? Retry? Caching?

Slide 47

Slide 47 text

Don't forget about writes: Conflicts? Write Coordination? Latency Compensation? State Sync?

Slide 48

Slide 48 text

Nah... We can solve this! Let's combine X + Y + Z and solve it!

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

Want to introduce changes ??? First learn about the entire project … :(

Slide 51

Slide 51 text

- How to fetch data - How to coordinate requests - How to coordinate writes - How to handle retries/errors - How to keep server/app in sync - How to update view with changes - How to cache data - How to keep that all in your head - How to …. - Your App What you had to think about:

Slide 52

Slide 52 text

- What data to fetch - Your App What you want to think:

Slide 53

Slide 53 text

Focus on what matters most! Relay make easy for developers to focus on the product and forget about data access nuances

Slide 54

Slide 54 text

Declarative Colocation Mutations Principles

Slide 55

Slide 55 text

Declarative The component describe what it want

Slide 56

Slide 56 text

// Story.js export default class Story extends React.Component { render() { var story = this.props.story; return ( {story.author.name} {story.text} ); } }

Slide 57

Slide 57 text

fragment on Story { text, author { name, profilePicture { uri } } }

Slide 58

Slide 58 text

export class Story extends Component { … } export default Relay.createContainer(Story, { fragments: { story: () => Relay.QL` fragment on Story { author { name profilePicture { uri } } text } `, }, });

Slide 59

Slide 59 text

export class Story extends React.Component { ... } export default Relay.createContainer(Story, { fragments: { story: () => Relay.QL` fragment on Story { author { ... } } `, }, }); Colocation

Slide 60

Slide 60 text

Easy to compose

Slide 61

Slide 61 text

export class NewsFeed extends Component { … } export default Relay.createContainer(NewsFeed, { fragments: { feed: () => Relay.QL` fragment on Feed { stories(first: $count) { // fetch viewer's stories edges { // traverse the graph node { ${Story.getFragment('story')} // compose child fragment } } } } `, }, });

Slide 62

Slide 62 text

class FeedRoute extends Relay.Route { static routeName = "FeedRoute"; static queries = { feed: () => Relay.QL` query { userFeed(uid: $userID) } `, }; } var feedRoute = new FeedRoute({userID: '123'}); Query Routes

Slide 63

Slide 63 text

ReactDOM.render( , domElement ); Root Containers

Slide 64

Slide 64 text

A common problem: Pagination

Slide 65

Slide 65 text

export default Relay.createContainer(NewsFeed, { initialVariables: { count: 3 }, fragments: { feed: () => Relay.QL` fragment on Feed { stories(first: $count) { ... } } `, }, });

Slide 66

Slide 66 text

class NewsFeed extends React.Component { render() { ... } loadMore() { var count = this.props.relay.variables.count; this.props.relay.setVariables({ count: count + 5, }); } }

Slide 67

Slide 67 text

followers(first: Int, last: String) { edges { node // the actual follower object, cursor // node identifier in the edge }, pageInfo { hasNextPage, lastCursor } } Pagination: How it works?

Slide 68

Slide 68 text

export default Relay.createContainer(Story, { fragments: { story: () => Relay.QL` fragment on Story { author { name followers(first: $limit) @include(if: $isDesktop) { ... } } text } `, }, }); Directives

Slide 69

Slide 69 text

Mutations

Slide 70

Slide 70 text

getMutation() { ... } getFatQuery() { ... } getConfigs() { ... } getVariables() { ... } Defining a mutation

Slide 71

Slide 71 text

export default class LikePostMutation extends Relay.Mutation { getMutation() { ... } getVariables() { ... } getConfigs() { ... } getFatQuery() { ... } } Defining the mutation

Slide 72

Slide 72 text

getMutation() { return Relay.QL`mutation{ likePost // `likePost` mutation must be defined on the server }`; } getMutation()

Slide 73

Slide 73 text

getVariables() { return { id: this.props.post.postId, like: this.props.like }; } getVariables()

Slide 74

Slide 74 text

getConfigs() { return [{ type: 'FIELDS_CHANGE', fieldIDs: { post: this.props.post.id } }]; } getConfigs()

Slide 75

Slide 75 text

getFatQuery() { return Relay.QL` fragment on LikePostPayload { post { id, likesCounter }, } `; } getFatQuery()

Slide 76

Slide 76 text

export class Story extends React.Component { handleEditPost() { const onFailure = () => {}; const onSuccess = () => {}; Relay.Store.commitUpdate(new LikePostMutation({ post: this.props.post, like: true }), {onFailure, onSuccess}); } } Sending the mutation

Slide 77

Slide 77 text

getOptimisticResponse() { return { post: { id: this.props.post.id, likesCounter: this.props.post.likesCounter + 1 } } } getOptimisticResponse()

Slide 78

Slide 78 text

interface Node { id: ID! } type Post extends Node { id: ID!, … // post fields } Object Tracking:

Slide 79

Slide 79 text

- Server-side rendering support - React Router integration - Babel Plugin - Active development: - Subscription (live) on the work - Client state is being discussed Important Details

Slide 80

Slide 80 text

- Work well with others tools - Flux, Redux, etc - Patterns are still emerging Not a silver bullet

Slide 81

Slide 81 text

Question?