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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Helielson
January 29, 2016
Programming
190
2
Share
GraphQL and Relay
Concepts, Spec and how we are using it at jusbrasil.com.br
Helielson
January 29, 2016
More Decks by Helielson
See All by Helielson
Relay @ Jusbrasil
helielson
0
170
Component-based development with React
helielson
1
150
React - A JavaScript library for building user interfaces
helielson
9
1.9k
Other Decks in Programming
See All in Programming
LLM Plugin for Node-REDの利用方法と開発について
404background
0
150
プロパティの順序で型推論が壊れる!? TypeScript6.0の修正からContext-Sensitivityの仕組みを追う
bicstone
2
1.3k
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
460
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
160
AIとRubyの静的型付け
ukin0k0
0
510
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
180
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
260
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.5k
ReactとSvelteのその先、Ripple-TS / Beyond React and Svelte: Ripple-TS
ssssota
3
1.9k
Modding RubyKaigi for Myself
yui_knk
0
860
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
260
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
463
34k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
550
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
200
74k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
840
Art, The Web, and Tiny UX
lynnandtonic
304
22k
How to Ace a Technical Interview
jacobian
281
24k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
350
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Exploring anti-patterns in Rails
aemeredith
3
380
Six Lessons from altMBA
skipperchong
29
4.3k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
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?