Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GraphQL and Relay
Search
Helielson
January 29, 2016
Programming
2
180
GraphQL and Relay
Concepts, Spec and how we are using it at jusbrasil.com.br
Helielson
January 29, 2016
Tweet
Share
More Decks by Helielson
See All by Helielson
Relay @ Jusbrasil
helielson
0
160
Component-based development with React
helielson
1
140
React - A JavaScript library for building user interfaces
helielson
9
1.9k
Other Decks in Programming
See All in Programming
Android端末で実現するオンデバイスLLM 2025
masayukisuda
1
170
FindyにおけるTakumi活用と脆弱性管理のこれから
rvirus0817
0
530
Zendeskのチケットを Amazon Bedrockで 解析した
ryokosuge
3
310
RDoc meets YARD
okuramasafumi
4
170
ProxyによるWindow間RPC機構の構築
syumai
3
1.2k
奥深くて厄介な「改行」と仲良くなる20分
oguemon
1
560
@Environment(\.keyPath)那么好我不允许你们不知道! / atEnvironment keyPath is so good and you should know it!
lovee
0
120
Processing Gem ベースの、2D レトロゲームエンジンの開発
tokujiros
2
130
Laravel Boost 超入門
fire_arlo
3
220
もうちょっといいRubyプロファイラを作りたい (2025)
osyoyu
1
450
1から理解するWeb Push
dora1998
7
1.9k
チームのテスト力を鍛える
goyoki
3
730
Featured
See All Featured
A better future with KSS
kneath
239
17k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
61k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Building a Modern Day E-commerce SEO Strategy
aleyda
43
7.6k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.5k
BBQ
matthewcrist
89
9.8k
How GitHub (no longer) Works
holman
315
140k
Building an army of robots
kneath
306
46k
The Pragmatic Product Professional
lauravandoore
36
6.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.9k
Practical Orchestrator
shlominoach
190
11k
Transcript
GraphQL and Relay
@helielson @hyetho @rodrigopr @rodrigoropr
Topics - GraphQL What is it? Motivation Spec Implementations How
we use it What is coming
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.
Why invent something new? What about REST and Ad hoc
endpoints?
REST problems - Multiple round trips to render single views
- Receives unnecessary data - Payloads tend to grow over time for all clients
- Code duplication - API changes with client need -
Hard to scale with multiple clients - Hard to keep backwards compatibility Ad hoc endpoints (view oriented)
How we think about data? - Not tables, joins or
URIs - But: - Objects - Properties - Relationships - What, not How
GraphQL
- Product-centric - Hierarchical - Client-specified queries - Strongly-typed Principles:
Product-centric
Hierarchical
{ post(id: 65) { title, votes, author { name, avatar
} } } Hierarchical
{ post(id: 65) { title, votes, author { name, avatar
} } } Hierarchical { "post": { "title": "Post title", "votes": 100, "author" { "name": "Didi", "avatar": "http://x.jpg" } } }
Strong-Typing
Client-specific Queries
Not tied to: - Language - Framework - Database -
Protocol
Schema - Think as a Graph - Define structure of
nodes (properties) - How they are connected
Schema User { name: String! email: String! followers: [User] isFriendOf(otherEmail:
String!): Boolean }
Schema query { post(postId: Int!): Post! user(email: String!): User! me:
User }
Type System - Interface - Object - Enum - Union
- List - Scalars: - String, Int, Boolean
Query language { user(email: "
[email protected]
") { name followers { name
} } }
query { user(email: "
[email protected]
") { ...userInfo followers { ...userInfo }
} } fragment userInfo on User { name, email lastPosts { ...somePostFrament } }
fragment petInfo on Pet { petName, owner { name }
… on Dog { noiseVolume: barkVolume } … on Cat { noiseVolume: meowVolume } }
Variables query houseTrainedQuery($atOtherHomes: Boolean) { dog { isHousetrained(atOtherHomes: $atOtherHomes) }
}
Fragment directives fragment maybeFragment on Query @include(if: $condition) { me
{ name } }
Fragment directives query myQuery($someTest: Boolean) { experimentalField @skip(if: $someTest) }
Mutation mutation { submitComment(postId: 1, user: "...", content: "") {
createdComment { id, url } } }
Open to optimizations - Batch - Cache - "DataLoader is
the true" http://github.com/facebook/dataloader
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
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
What's coming next? - Open source movement - Improve data
coverage - Provide authorization in schema (acl) - Mutation (done) - Object authorization - Field authorization
Questions?
Relay
Topics - Relay What is it? Motivation Spec Implementation How
we use it What is coming
Definition A javascript framework for building data-driven react applications
Dispatcher View Store Action
Dispatcher View Store Action Server
Let's make an App !! Will be easy !!!!
None
How to load data from server?
<TopicTag /> <Feed /> <Document />
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
A big payload /feed_with_topics_max_tree_documents One custom endpoint that loads everything
/feed?topics=true&max_documents=3 Multiple custom endpoints
And what about: Pagination? Ordering? Error handling? Retry? Caching?
Don't forget about writes: Conflicts? Write Coordination? Latency Compensation? State
Sync?
Nah... We can solve this! Let's combine X + Y
+ Z and solve it!
None
Want to introduce changes ??? First learn about the entire
project … :(
- 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:
- What data to fetch - Your App What you
want to think:
Focus on what matters most! Relay make easy for developers
to focus on the product and forget about data access nuances
Declarative Colocation Mutations Principles
Declarative The component describe what it want
// Story.js export default class Story extends React.Component { render()
{ var story = this.props.story; return ( <View> <Image uri={story.author.profilePicture.uri} /> <Text>{story.author.name}</Text> <Text>{story.text}</Text> </View> ); } }
fragment on Story { text, author { name, profilePicture {
uri } } }
export class Story extends Component { … } export default
Relay.createContainer(Story, { fragments: { story: () => Relay.QL` fragment on Story { author { name profilePicture { uri } } text } `, }, });
export class Story extends React.Component { ... } export default
Relay.createContainer(Story, { fragments: { story: () => Relay.QL` fragment on Story { author { ... } } `, }, }); Colocation
Easy to compose
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 } } } } `, }, });
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
ReactDOM.render( <Relay.RootContainer Component={Feed} route={feedRouter} renderLoading={...} // optional renderFailure={...} // optional
renderFetched={...} // optional />, domElement ); Root Containers
A common problem: Pagination
export default Relay.createContainer(NewsFeed, { initialVariables: { count: 3 }, fragments:
{ feed: () => Relay.QL` fragment on Feed { stories(first: $count) { ... } } `, }, });
class NewsFeed extends React.Component { render() { ... } loadMore()
{ var count = this.props.relay.variables.count; this.props.relay.setVariables({ count: count + 5, }); } }
followers(first: Int, last: String) { edges { node // the
actual follower object, cursor // node identifier in the edge }, pageInfo { hasNextPage, lastCursor } } Pagination: How it works?
export default Relay.createContainer(Story, { fragments: { story: () => Relay.QL`
fragment on Story { author { name followers(first: $limit) @include(if: $isDesktop) { ... } } text } `, }, }); Directives
Mutations
getMutation() { ... } getFatQuery() { ... } getConfigs() {
... } getVariables() { ... } Defining a mutation
export default class LikePostMutation extends Relay.Mutation { getMutation() { ...
} getVariables() { ... } getConfigs() { ... } getFatQuery() { ... } } Defining the mutation
getMutation() { return Relay.QL`mutation{ likePost // `likePost` mutation must be
defined on the server }`; } getMutation()
getVariables() { return { id: this.props.post.postId, like: this.props.like }; }
getVariables()
getConfigs() { return [{ type: 'FIELDS_CHANGE', fieldIDs: { post: this.props.post.id
} }]; } getConfigs()
getFatQuery() { return Relay.QL` fragment on LikePostPayload { post {
id, likesCounter }, } `; } getFatQuery()
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
getOptimisticResponse() { return { post: { id: this.props.post.id, likesCounter: this.props.post.likesCounter
+ 1 } } } getOptimisticResponse()
interface Node { id: ID! } type Post extends Node
{ id: ID!, … // post fields } Object Tracking:
- Server-side rendering support - React Router integration - Babel
Plugin - Active development: - Subscription (live) on the work - Client state is being discussed Important Details
- Work well with others tools - Flux, Redux, etc
- Patterns are still emerging Not a silver bullet
Question?