2012 ⬢ Shallow experiences covered from design, mobile, front-end and backend develop to cloud deployments (AWS) ⬢ Fan of GraphQL/Relay of its beauty of API design since 2015 ⬢ Working at with Ruby, JavaScript (React.js) and playing Elixir ⬢ Former tech lead at Colorgy ! # @zetavg fb.me/pokaichang72
to get started ⬡ GraphQL client library overview ⬡ Intro to Relay ⬡ Demo: GraphQL & Relay on Rails https:/ /github.com/zetavg/RailsRelayTodoMVC Outline
to develop ⬡ Directly based on Wide World Web ⬡ URI as resource name (noun), HTTP method as action (verb) ⬡ We need documents: Swagger... ⬡ ...and type definitions: JSON Schema ⬡ ...and data relations: JSON API ⬡ Combine them all: API Blueprint, RAML
SPA or mobile apps: ⬡ Querying complex data efficiently is still hard ⬡ We may come up with lots of endpoint versions ⬡ Or messy features on different endpoints ⬡ On purpose specs are hard to follow, without an clear interface, APIs tends to be hard to reuse and maintain ⬡ Writing code to fetch and store data is annoying ⬡ Caching is hard cause there's no explicit schema ⬡ Co-working may be messy cause there's no schema
2012 - Used for Facebook mobile app ⬡ 2015 - Publicly released ⬡ 2017 - Now: GraphQL & Relay re-licensed under MIT ⬢ Normally uses a single endpoint URL ( POST /graphql )
to get started ⬡ GraphQL client library overview ⬡ Intro to Relay ⬡ Demo: GraphQL & Relay on Rails https:/ /github.com/zetavg/RailsRelayTodoMVC Outline
{ viewer { name birthday { month day } following { name } } } # GraphQL schema language type Query { viewer: User } type User { name: String! birthday: Date followers: [User] following: [User] } type Date { year: Integer month: Integer day: Integer }
{ viewer: User } type User { name: String! birthday: Date followers: [User] following: [User] } type Date { year: Integer month: Integer day: Integer } [<thing>] means an array of <thing> objects ! means that the field is non-nullable
fields that a type must define to implement ⬢ Can be used for fragments interface Actor { id: ID! name: String! avatarUrl: String! } type User implements Actor { id: ID! name: String! avatarUrl: String! ... } type Bot implements Actor { id: ID! # Sample Query fragment actorFields on Actor { name bio avatarUrl } query { feed { actor { ...actorFields } verb
instead of query , and are ways how we can change the data ⬢ We can put the input data in arguments, changed nodes will be returned in the selectable payload ⬢ It’s a convention like RESTful GET/POST that clients rely on mutation { addComment(input: { subjectId: 1, body: "Hi." }) { subject { comments { body } } } }
to get started ⬡ GraphQL client library overview ⬡ Intro to Relay ⬡ Demo: GraphQL & Relay on Rails https:/ /github.com/zetavg/RailsRelayTodoMVC Outline
$ ㄎ ㄎ ㄎ ㄎ viewer { following { name } } d d d d d d d d $ $ $ $ $ Backend query { viewer { following { name } } } { "data": { "viewer": { "following": […] } } }
Repo Repo Repo name "Pokai Chang" "dotfiles" name repos name "Thing" name "Stuff" user(login: "zetavg") user(login: "zetavg")/repos[2] ⬡ Same path, same object Caching the query result
Repo Repo Repo name "Pokai Chang" "dotfiles" name repos name "Thing" name "Stuff" repo(owner: "zetavg", name: "dotfiles") Repo name "dotfiles" ⬡ Sometimes path assumption isn’t enough Caching the query result
Repo Repo Repo name "Pokai Chang" "dotfiles" name repos name "Thing" name "Stuff" repo(owner: "zetavg", name: "dotfiles") Repo name "dotfiles" Same object on different path ⬡ Sometimes path assumption isn’t enough Caching the query result
repo/dotfiles Repo name "dotfiles" repo/dotfiles Repo name "dotfiles" Query Root User Repo Repo user(login: "zetavg") "Pokai Chang" name repos name "Thing" name "Stuff" repo(owner: "zetavg", name: "dotfiles") repo/Thing repo/Stuff Caching the query result
Query Root User Repo Repo user(login: "zetavg") "Pokai Chang" name repos name "Thing" name "Stuff" repo(owner: "zetavg", name: "dotfiles") repo/Thing repo/Stuff Repo name "dotfiles" repo/dotfiles Caching the query result
⬡ Relay: we need the server to give a global id for nodes that need to be identified ⬡ Apollo: client defines a dataIdFromObject function that will be executed on every node ⬡ Fun fact: Relay stores each object it fetched in a key-value store with the object id or traverse path as key, any field that contains an object will actually be the key of the object, so two objects having the same id will be ensured the same by Implementation Caching the query result
effects ⬢ The changes made on the graph will be put on the response, the client is responsible to select the necessary parts mutation { renameRepo(input: { repoID: "…", name: "NewName" }) { repo { id name } } } Grab the changes that are made on the existing repo
effects ⬢ The changes made on the graph will be put on the response, the client is responsible to select the necessary parts ⬢ In general, we need to write an updater function to update the store with the payload: (oldState, payload) => newState ⬢ Relay and Apollo both has some conventions ⬡ Objects with matching identifier in the store will be updated automatically
of event as a similar way as how we do mutations ⬢ Mutations are client-made changes while Subscriptions are server-pushed updates ⬢ New query results will be pushed to the client when a event occurred subscription { todoItemAddedToList(todoListID: "…") { todoItem { name } } }
of event as a similar way as how we do mutations ⬢ Mutations are client-made changes while Subscriptions are server-pushed updates ⬢ New query results will be pushed to the client when a event occurred ⬢ GraphQL just tells us how things should work, we need to configure different implementations (WebSocket, APNS, GCM) of sending the data on different platforms