SlideShare a Scribd company logo
! # @zetavg

fb.me/pokaichang72
串串起前後端資料的橋樑

GraphQL 

& Relay
Q: 這個 app 需要多少 API
Endpoints?
Ans: 4
GET /api/todos.json
POST /api/todos.json
PATCH /api/todos/id.json
DELETE /api/todos/id.json
Q: 那這個 app 需要多少 API
Endpoints 呢?
/api/v1/posts.json
/api/v2/posts.json
/api/v3/posts.json
/api/v4/posts.json
/api/v65535/posts.json
⋯⋯
/api/posts.json
/api/posts.json?include=author
/api/posts.json?include=author,comments
/api/posts.json?cover=true&include=author,comments
/api/posts.json?cover=true&include=author,comments_with
API 應該是這樣
不是這樣
Q: 那這個 app 需要多少 API
Endpoints 呢?
Ans: 1
Ans: 1
GraphQL
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name": "Lucy",
"bio":"...",
"followers": [◌],
"repos": [◌, ◌]

}
$
{
"name": "Ja
"bio":"..."
"followers"
"repos": [◌
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Hello World",
"description": "...",
"stargazers": [◌, ◌]

}
!
{
"name": "Handy Ut
"description": ".
"stargazers": [◌]
}
!
{
"name": "Awes
"description"
"stargazers":
}
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{ }
{
"viewer": ◌

}
GraphQL
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name": "Lucy",
"bio":"...",
"followers": [◌],
"repos": [◌, ◌]

}
$
{
"name": "Ja
"bio":"..."
"followers"
"repos": [◌
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Hello World",
"description": "...",
"stargazers": [◌, ◌]

}
!
{
"name": "Handy Ut
"description": ".
"stargazers": [◌]
}
!
{
"name": "Awes
"description"
"stargazers":
}
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{ }
{
"viewer": ◌

}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
$
{
"name"
"bio":
"follo
"repos
}
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
{ }
{
"viewer": ◌

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$ dd
dd
dd
dd
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
{ }
{
"viewer": ◌

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
$
$
$
$
$
$
!
!
{
"name": "Thi
"description
"stargazers"
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
{ }
{
"viewer": ◌

}
$ $ $
$ $ $
$ $ $
$ $
/
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
⬡ GraphQL 簡介
⬡ Relay ⼿手感評測
⬡ Relay 基本使⽤用
⬡ 全端案例例:GraphQL & Relay on Rails

https://github.com/zetavg/RailsRelayTodoMVC
不會講到跟 Apollo 的比較
Outline
⬡ GraphQL 簡介
⬡ Relay ⼿手感評測
⬡ Relay 基本使⽤用
⬡ 全端案例例:GraphQL & Relay on Rails

https://github.com/zetavg/RailsRelayTodoMVC
不會講到跟 Apollo 的比較
Outline
基本查詢
⬢ 最外層⼀一定是 query
⬢ 問什什麼得什什麼
{
"data": {
"viewer": {
"name": "Pokai Chang"
}
}
}
query {
viewer {
name
}
}
查詢更更多
⬢ 巢狀狀選取欄欄位 (field)
{
"data": {
"viewer": {
"name": "Pokai Chang",
"birthday": {
"month": 7,
"day": 2
}
}
}
}
query {
viewer {
name
birthday {
month
day
}
}
}
巢狀狀查更更多
⬢ 底下的資料 (node) 可能是同⼀一種類型 (type)
{
"data": {
"viewer": {
"name": "Pokai Chang",
"following": [
{ "name": "..." },
{ "name": "..." },
{ "name": "..." }
]
}
}
}
query {
viewer {
name
following {
name
}
}
}
巢狀狀查更更多多多多
⬢ 可以幹奇怪的事⋯⋯
{
"data": {
"viewer": {
"name": "Pokai Chang",
"following": [
{
"name": "…",
"followers": [
{
"name": "Pokai Chang",
"following": [
{
"name": "…",
"followers": [
{
"name": "Pokai C
query {
viewer {
name
following {
name
followers {
following {
name
followers {
name
}
}
}
}
}
}
型別定義即⽂文件
query {
viewer {
name
birthday {
month
day
}
following {
name
}
}
}
type Query {
viewer: User
}
type User {
name: String
birthday: Date
followers: [User]
following: [User]
}
type Date {
year: Integer
month: Integer
day: Integer
}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name": "Lucy",
"bio":"...",
"followers": [◌],
"repos": [◌, ◌]

}
$
{
"name": "Ja
"bio":"..."
"followers"
"repos": [◌
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Hello World",
"description": "...",
"stargazers": [◌, ◌]

}
!
{
"name": "Handy Ut
"description": ".
"stargazers": [◌]
}
!
{
"name": "Awes
"description"
"stargazers":
}
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{ }
{
"viewer": ◌

}
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
{ }
{
"viewer": ◌

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
query {
viewer {
name
bio
}
}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
{ }
{
"viewer": ◌

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
query {
viewer {
name
bio
followers {
name
}
}
}
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
{ }
{
"viewer": ◌

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
query {
viewer {
name
bio
followers {
name
}
repos {
name
stargazers {
name
}
}
}
}
{ }
{
"viewer": ◌

}
!
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name"
"bio":
"follo
"repos
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Thi
"description
"stargazers"
}
!
query {
viewer {
name
bio
followers {
name
}
repos {
name
stargazers {
name
}
}
girlfriend {
name
}
}
}
'
query {
viewer {
name
bio
followers {
name
}
repos {
name
stargazers {
name
}
}
girlfriend {
name
}
}
}
{
"errors": [
{
"message": "Field 'girlfriend' doesn't

exist on type ‘User’",
...
}
]
}
'
Arguments 參參數
⬢ 每個 field 會定義可⽤用的參參數
query {
user(id: 1) {
name
}
}
Arguments 參參數
⬢ 也可以做巢狀狀查詢
query {
user(id: 1) {
name
repo(name: "awesome-graphql") {
name
description
}
}
}
Fragment 片段
fragment profileFields on User {
name
bio
avatarUrl
}
query {
viewer {
...profileFields
}
user(id: 1) {
...profileFields
}
}
先把固定會⽤用到的欄欄位
存成有意義的片段
改資料 ? Mutation
⬢ query 改成 mutation,data 放在 arguments
⬢ 其實就像 HTTP GET/POST,只是慣例例,沒有硬性限制
mutation {
addComment(input: { subjectId: 1, body: "Hi." }) {
subject {
comments {
body
}
}
}
}
graphql.org
⬡ GraphQL 簡介
⬡ Relay ⼿手感評測
⬡ Relay 基本使⽤用
⬡ 全端案例例:GraphQL & Relay on Rails

https://github.com/zetavg/RailsRelayTodoMVC
不會講到跟 Apollo 的比較
Outline
無限捲軸
Caching
Prefetch Caching
Server Data Updating
Optimistic Update
Realtime Update
facebook.github.io/relay
Relay



Relay Modern
(Relay 1.0)
const View = (data) => UI
Redux 資料流
View
State
subscribe
Redux Store
Redux 資料流
View
State
Reducer
Action
subscribe
prevState
Redux 資料流
View
State
Reducer
Action
subscribe
prevState
Backend ?
Redux 資料流 ?
View
State
Reducer
Action
subscribe
prevState
Backend
Action
Action
Action
Redux 資料流 ?
View
Action
Action
Action
Action
Backend
State
State
State
Reducer
Reducer Reducer
Reducer
???
???
$
{
"name": "Neson",
"bio":"Yet another geek.",
"followers": [◌, ◌, ◌],
"repos": [◌, ◌, ◌]

}
$
{
"name": "Lucy",
"bio":"...",
"followers": [◌],
"repos": [◌, ◌]

}
$
{
"name": "Ja
"bio":"..."
"followers"
"repos": [◌
}
$
{
"name": "Pusheen",
"bio":"Nyan nyan nyan~",
"followers": [◌],
"repos": [◌]

}
!
{
"name": "Thing Compiler",
"description": "...",
"stargazers": [◌, ◌, ◌]

}
!
{
"name": "Hello World",
"description": "...",
"stargazers": [◌, ◌]

}
!
{
"name": "Handy Ut
"description": ".
"stargazers": [◌]
}
!
{
"name": "Awes
"description"
"stargazers":
}
!
{
"name": "Todo",
"description": "...",
"stargazers": [◌]

}
!
{ }
{
"viewer": ◌

}
GraphQL
Relay 的狀狀況
View
$
$
$ $
$
dd
$ $ $ $
dd
dd
dd
Relay Store
Relay 的狀狀況
View
$
$ $
$
dd
$ $ $ $
dd
dd
dd
Relay Store
viewer {
name
bio
}
$
Backend
query {
viewer {
name
bio
}
}
{
"data": {
"viewer": {
"name": "…",
"Bio": "…"
}
}
}
Relay 的狀狀況
View
ㄎㄎㄎㄎ$
$ $
$
dd
$ $ $ $
dd
dd
dd
Relay Store
viewer {
name
bio
}
$
Relay 的狀狀況
View
ㄎㄎㄎㄎ
dd
dd
dd
dd
$ $
$ $ $ $ $
viewer {
name
bio
}
$
$
viewer {
followers {
name
}
}
Backend
query {
viewer {
followers {
name
}
}
}
{
"data": {
"viewer": {
"followers": […]
}
}
}
Relay Store
Request only the diff!
Relay 的狀狀況
View
ㄎㄎㄎㄎ
dd
dd
dd
dd
$ $
$ $ $ $ $
viewer {
name
bio
}
$
$
viewer {
followers {
name
}
}
Relay 的狀狀況
viewer {
name
bio
}
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
viewer {
followers {
name
}
}
dd
dd
dd
dd
viewer {
repos {
name
description
}
}
Backend
query {
viewer {
repos {
name
description
}
}
}
{
"data": {
"viewer": {
"repos": […]
}
}
}
Relay 的狀狀況
viewer {
name
bio
}
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
viewer {
followers {
name
}
}
dd
dd
dd
dd
viewer {
repos {
name
description
}
}
Relay 的狀狀況
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
dd
dd
dd
dd
RenameRepoMutation(
repoID: "…",
name: ""
)
Relay 的狀狀況
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
dd
dd
dd
dd
RenameRepoMutation(
repoID: "…",
name: ""
)
Optimistic Updater
Relay 的狀狀況
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
dd
dd
dd
dd
RenameRepoMutation(
repoID: "…",
name: ""
)
Optimistic UpdaterBackend
Updater
Relay 的狀狀況
View
$
ㄎㄎㄎㄎ$
$ $
$ $ $ $ $
dd
dd
dd
dd
RenameRepoMutation(
repoID: "…",
name: ""
)
Optimistic UpdaterBackend
Updater
想分⾴頁 ? Connections
⬢ 游標分⾴頁法:Relay Cursor Connections
query {
viewer {
friends(first: 10, after: "someCursor") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
}
}
}
}
Edge (UserEdgeType)
Node (UserType)
{ … }
Cursor
游標 Connection
Edges
Edge (UserEdgeType)
Node (UserType)
{ … }
Cursor
Edge (UserEdgeTy
Node (UserType
{ … }
Cursor
Page Info
起始游標
⬢ Offset based pagination
⬢ Cursor based pagination
Why Cursor?
page 1 page 2
page 1 page 2
page 3
page 3
' 壞ㄌ
next 5next 5
⬡ Relay 可信的 Optimistic Updater 機制可以做
「連線問題時重試」甚⾄至離線更更動上線後同步
⬡ Relay 的 backend 不⼀一定要是 server,也許可以
是裝置上的 database
⬡ 再狂⼀一點,也許我們還能透過⾃自⼰己實作 Relay
RecordSource 組出這樣的架構:
Fun Things to Try
RelayRelay ViewServer
Client DB Memory
Optimistic Update
Management
{歡樂 Demo 時間}
適⽤用情況
⬢ Data driven,data 越多越雜,投資越划算
⬢ React app
⬢ 略略懂後端
⬢ 踩雷的勇氣
Relay Environment
Handler Provider
Network Layer
Store
Record Source
GraphQL Endpoint
Query Renderer
Container
Component
Fragment
Query
跟後端不熟?
⬡ GraphQL 簡介
⬡ Relay ⼿手感評測
⬡ Relay 基本使⽤用
⬡ 全端案例例:GraphQL & Relay on Rails

https://github.com/zetavg/RailsRelayTodoMVC
不會講到跟 Apollo 的比較
Outline
在 React 專案中安裝 Relay
$ yarn add react-relay
安裝 GraphQL 語法識別外掛
$ yarn add --dev babel-plugin-relay
記得⼿手動加 Babel Plugin
⬢ 編輯 .eslintrc 或 package.json
"plugins": [
"relay",
]
安裝 Relay GraphQL 編譯器
$ yarn add --dev relay-compiler
使⽤用 relay-compiler
⬢ 在 JavaScript 裡寫的 GraphQL 需要被事先編譯⋯⋯



⬢ 改了了 graphql`…` tag 裡⾯面的內容後都要跑⼀一次
⬢ 或是加上 --watch 參參數監看變化
$ relay-compiler --src ./src --schema ./schema.graphql
源碼⽬目錄 GraphQL Schema 檔位置
import { Environment } from ‘relay-runtime’
const environment = new Environment({
network,
store,
})
export default environment
環境準備
Relay Environment
Handler Provider
Network Layer
Store
Record Source
GraphQL Endpoint
Network Layer
Store
⬢ 先看整個環境⋯⋯
import { Network } from ‘relay-runtime'
const API_ENDPOINT = 'https://api.github.com/graphql'
const fetchQuery = (operation, variables) => {
return fetch(API_ENDPOINT, {
method: 'POST',
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => response.json())
}
const network = Network.create(fetchQuery)
exports default network
Relay 網路路層
⬢ 給⼀一個溝通介⾯面,⼀一般就是包裝 fetch
Relay Environment
Handler Provider
Network Layer
Store
Record Source
GraphQL Endpoint
import {
RecordSource,
Store,
} from 'relay-runtime'
const source = new RecordSource()
const store = new Store(source)
export default store
Relay 倉儲
Relay Environment
Handler Provider
Network Layer
Store
Record Source
GraphQL Endpoint
⬢ Relay 內建具備 garbage collection 的 in-memory
record source
以上,前置準備完成 🎉
const MyProfile = () => (
<QueryRenderer
environment={environment}
query={graphql`
query MyProfileQuery {
viewer {
name
}
}
`}
render={({ error, props }) => {
if (error) {
return <Text>{error.message}</Text>
} else if (props) {
return <Text>Hello, {props.viewer.name}!</Text>
}
return <Text>Loading...</Text>
}}
/>
)
基本招 QueryRenderer
可以設計載入中假畫⾯面
注意名字有規定⽤用 "[檔案名稱]Query"
Relay Environment
Handler Provider
Network Layer
Store
Record Source
GraphQL Endpoint
Query Renderer
Component
Query
const UserProfileComponent = ({ user }) => (
<Text>Hello, {user.name}!</Text>
)
const UserProfile = createFragmentContainer(
UserProfileComponent,
graphql`
fragment UserProfile_user on User {
name
login
avatarUrl
}
`,
)
export default UserProfile
拆元件 FragmentContainer
注意名字也有規定⽤用 "[檔案名稱]_[prop 名稱]"
Relay Environment
Store
Query Renderer
Container
Component
Fragment
Query
拆元件 FragmentContainer
直接引⽤用定義在 Container 裡的 Fragment
Relay Environment
Store
Query Renderer
Container
Component
Fragment
Query
import MyProfile from '...'
const MyProfile = () => (
<QueryRenderer
environment={environment}
query={graphql`
query MyProfileQuery {
viewer {
...UserProfile_user
}
}
`}
render={({ error, props }) => {
if (error) {
return <Text>{error.message}</Text>
} else if (props) {
return <MyProfile user={props.viewer} />
}
return <Text>Loading...</Text>
}}
/>
)
Component Tree 層層疊疊
Query Renderer
Container Fragment
Query
ContainerContainer
Component Component
FragmentFragment
const UserProfileComponent = ({ user }) => (
<View>
<UserName user={user} />
<UserBio user={user} />
</View>
)
const UserProfile = createFragmentContainer(
UserProfileComponent,
graphql`
fragment UserProfile_user on User {
...UserName_user
...UserBio_user
}
`,
)
const UserNameComponent = ({ user }) => (
<Text>Hello, {user.name}!</Text>
)
const UserName = createFragmentContainer(
UserNameComponent,
graphql`
fragment UserName_user on User {
name
avatarUrl
}
`,
)
const UserBioComponent = ({ user }) => (
<Text>{user.bio}</Text>
)
const UserBio = createFragmentContainer(
UserBioComponent,
graphql`
fragment UserBio_user on User {
bio
}
`,
)
特種 Container
⬢ RefetchContainer
⬡ 提供 instance method 可以改⽤用不同 arguments 索取資料
⬢ PaginationContainer
⬡ RefetchContainer 進化版
⬡ ⽤用 Relay Connection 做分⾴頁專⽤用
⬡ 可以做出 loadMore()、refresh() 等 method 給無限捲軸和
pull to refresh 使⽤用
Mutation
const mutation = graphql`
mutation AddCommentMutation(
$input: AddCommentInput!
) {
addComment(input: $input) {
clientMutationId
commentEdge {
cursor
node {
id
body
}
}
subject {
id
commentsCount
}
}
}
`
let variables = {
input: {
subjectId: "aGVsbG8=",
body: "Hello Relay",
}
}
commitMutation(
environment,
{
mutation,
variables,
onCompleted: (response) => {
console.log('Success!')
},
onError: (err) => {
console.error(err)
},
},
)
1
2
3
1
2
3
⼀一樣有命名規定
宣告 $input 變數以及型別,內容可以在使⽤用時再指定
與 query ⼀一樣列列出欄欄位,這裡需要列列出所有 mutation 執⾏行行後會變更更或新增的資料
2
⬢ 還有需要做的事⋯⋯
Mutation Updater
const mutation = graphql`
mutation AddCommentMutation(
$input: AddCommentInput!
) {
addComment(input: $input) {
clientMutationId
commentEdge {
cursor
node {
id
body
}
}
subject {
id
commentsCount
}
}
}
`
Mutation 執⾏行行後,我們需要把新的 edge 安插到

某個 subject 底下的 comments connection
若若在 payload root 發現具有 id 的 node,

Relay 慣例例會幫我們更更新好 store 中相應的 node
Mutation Updater
commitMutation(
environment,
{
mutation,
variables: { ... },
updater: (store) => {
const payload = store.getRootField('addComment')
const newEdge = payload.getLinkedRecord('commentEdge')
const subject = payload.getLinkedRecord('subject')
const conn =
ConnectionHandler.getConnection(subject, ‘commentsConnection')
ConnectionHandler.insertEdgeAfter(conn, newEdge)
},
optimisticUpdater: (store) => {
…
},
},
)
可⾃自訂 store 的 update ⽅方式
Mutation Updater
ConnectionHandler.insertEdgeAfter(conn, newEdge)
},
optimisticUpdater: (store) => {
const subject = store.get(subjectID)
const newCommentID = `client:newComment:${tempID++}`
const newNode = store.create(newCommentID, 'Comment')
newNode.setValue(newCommentID, 'id')
newNode.setValue(variables.input.body, 'body')
const newEdge = store.create(
`client:newCommentEdge:${tempID++}`,
'TodoItemEdge',
)
newEdge.setLinkedRecord(newNode, 'node')
const conn = ConnectionHandler.getConnection(subject, 'commentsConnection')
ConnectionHandler.insertEdgeAfter(conn, newEdge)
subject.setValue(
subject.getValue('commentsCount') + 1,
'commentsCount',
)
},
},
)
製作出暫時的 node
製作出暫時的 edge
把暫時的 edge 安插進 connection
⼿手動更更新計數器
⬡ GraphQL 簡介
⬡ Relay ⼿手感評測
⬡ Relay 基本使⽤用
⬡ 全端案例例:GraphQL & Relay on Rails

https://github.com/zetavg/RailsRelayTodoMVC
不會講到跟 Apollo 的比較
Outline
(GraphQL + Relay) on Rails
(GraphQL + Relay) on Rails
全端⼀一天可以寫完,拿來來做 RN 更更顯神⼒力力
(GraphQL + Relay) on Rails
Debug 省下的時間可以拿來來調各種 1px
Image source: https://blog.codinghorror.com/learn-to-read-the-source-luke/
請⾒見見 https://github.com/zetavg/RailsRelayTodoMVC
Thanks + Q&A

More Related Content

What's hot

01. Kubernetes-PPT.pptx
01. Kubernetes-PPT.pptx01. Kubernetes-PPT.pptx
01. Kubernetes-PPT.pptx
TamalBanerjee16
 
Docker Basics
Docker BasicsDocker Basics
Docker Basics
Eueung Mulyana
 
Google Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep diveGoogle Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep dive
Akash Agrawal
 
Docker Networking Overview
Docker Networking OverviewDocker Networking Overview
Docker Networking Overview
Sreenivas Makam
 
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
InfluxData
 
MySQL Operator for Kubernetes
MySQL Operator for KubernetesMySQL Operator for Kubernetes
MySQL Operator for Kubernetes
Kenny Gryp
 
Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)
Opsta
 
RunX: deploy real-time OSes as containers at the edge
RunX: deploy real-time OSes as containers at the edgeRunX: deploy real-time OSes as containers at the edge
RunX: deploy real-time OSes as containers at the edge
Stefano Stabellini
 
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in ProductionUpgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
Cloudera, Inc.
 
An Introduction to Kubernetes
An Introduction to KubernetesAn Introduction to Kubernetes
An Introduction to Kubernetes
Imesh Gunaratne
 
Minio Cloud Storage
Minio Cloud StorageMinio Cloud Storage
Minio Cloud Storage
Minio
 
Ceph Introduction 2017
Ceph Introduction 2017  Ceph Introduction 2017
Ceph Introduction 2017
Karan Singh
 
Kubernetes 1001
Kubernetes 1001Kubernetes 1001
Kubernetes 1001
HungWei Chiu
 
containerd the universal container runtime
containerd the universal container runtimecontainerd the universal container runtime
containerd the universal container runtime
Docker, Inc.
 
Containerd + buildkit breakout
Containerd + buildkit breakoutContainerd + buildkit breakout
Containerd + buildkit breakout
Docker, Inc.
 
Kubernetes #6 advanced scheduling
Kubernetes #6   advanced schedulingKubernetes #6   advanced scheduling
Kubernetes #6 advanced scheduling
Terry Cho
 
Docker.pptx
Docker.pptxDocker.pptx
Docker.pptx
balaji257
 
YAML Tips For Kubernetes by Neependra Khare
YAML Tips For Kubernetes by Neependra KhareYAML Tips For Kubernetes by Neependra Khare
YAML Tips For Kubernetes by Neependra Khare
CodeOps Technologies LLP
 
Helm Charts Security 101
Helm Charts Security 101Helm Charts Security 101
Helm Charts Security 101
Deep Datta
 
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red HatMultiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
OpenStack
 

What's hot (20)

01. Kubernetes-PPT.pptx
01. Kubernetes-PPT.pptx01. Kubernetes-PPT.pptx
01. Kubernetes-PPT.pptx
 
Docker Basics
Docker BasicsDocker Basics
Docker Basics
 
Google Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep diveGoogle Kubernetes Engine (GKE) deep dive
Google Kubernetes Engine (GKE) deep dive
 
Docker Networking Overview
Docker Networking OverviewDocker Networking Overview
Docker Networking Overview
 
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
Jacob Marble [InfluxData] | Observability with InfluxDB IOx and OpenTelemetry...
 
MySQL Operator for Kubernetes
MySQL Operator for KubernetesMySQL Operator for Kubernetes
MySQL Operator for Kubernetes
 
Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)
 
RunX: deploy real-time OSes as containers at the edge
RunX: deploy real-time OSes as containers at the edgeRunX: deploy real-time OSes as containers at the edge
RunX: deploy real-time OSes as containers at the edge
 
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in ProductionUpgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
Upgrade Without the Headache: Best Practices for Upgrading Hadoop in Production
 
An Introduction to Kubernetes
An Introduction to KubernetesAn Introduction to Kubernetes
An Introduction to Kubernetes
 
Minio Cloud Storage
Minio Cloud StorageMinio Cloud Storage
Minio Cloud Storage
 
Ceph Introduction 2017
Ceph Introduction 2017  Ceph Introduction 2017
Ceph Introduction 2017
 
Kubernetes 1001
Kubernetes 1001Kubernetes 1001
Kubernetes 1001
 
containerd the universal container runtime
containerd the universal container runtimecontainerd the universal container runtime
containerd the universal container runtime
 
Containerd + buildkit breakout
Containerd + buildkit breakoutContainerd + buildkit breakout
Containerd + buildkit breakout
 
Kubernetes #6 advanced scheduling
Kubernetes #6   advanced schedulingKubernetes #6   advanced scheduling
Kubernetes #6 advanced scheduling
 
Docker.pptx
Docker.pptxDocker.pptx
Docker.pptx
 
YAML Tips For Kubernetes by Neependra Khare
YAML Tips For Kubernetes by Neependra KhareYAML Tips For Kubernetes by Neependra Khare
YAML Tips For Kubernetes by Neependra Khare
 
Helm Charts Security 101
Helm Charts Security 101Helm Charts Security 101
Helm Charts Security 101
 
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red HatMultiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
Multiple Sites and Disaster Recovery with Ceph: Andrew Hatfield, Red Hat
 

Similar to GraphQL & Relay - 串起前後端世界的橋樑

Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & Clients
Pokai Chang
 
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/RailsFinding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
Michael Reinsch
 
Effectively Testing Services on Rails - Railsconf 2014
Effectively Testing Services on Rails - Railsconf 2014Effectively Testing Services on Rails - Railsconf 2014
Effectively Testing Services on Rails - Railsconf 2014
neal_kemp
 
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
Codemotion
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
Ruby Meditation
 
Copy/paste detector for source code on javascript
Copy/paste detector for source code on javascript Copy/paste detector for source code on javascript
Copy/paste detector for source code on javascript
Andrey Kucherenko
 
Ams adapters
Ams adaptersAms adapters
Ams adapters
Bruno Alló Bacarini
 
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B) Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Michael Reinsch
 
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
apidays
 
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
apidays
 
GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za mało
MarcinStachniuk
 
WIRED and the WP REST API
WIRED and the WP REST APIWIRED and the WP REST API
WIRED and the WP REST API
kvignos
 
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
André Ricardo Barreto de Oliveira
 
Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk   Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk
OdessaJS Conf
 
Real-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @MoldcampReal-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @MoldcampAlexei Gorobets
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInauts
Wynn Netherland
 
Agile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collectionAgile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collection
JoEllen Carter
 
Elasticsearch in 15 Minutes
Elasticsearch in 15 MinutesElasticsearch in 15 Minutes
Elasticsearch in 15 Minutes
Karel Minarik
 
Elasticsearch in 15 minutes
Elasticsearch in 15 minutesElasticsearch in 15 minutes
Elasticsearch in 15 minutes
David Pilato
 
Elasticsearch intro output
Elasticsearch intro outputElasticsearch intro output
Elasticsearch intro output
Tom Chen
 

Similar to GraphQL & Relay - 串起前後端世界的橋樑 (20)

Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & Clients
 
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/RailsFinding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
 
Effectively Testing Services on Rails - Railsconf 2014
Effectively Testing Services on Rails - Railsconf 2014Effectively Testing Services on Rails - Railsconf 2014
Effectively Testing Services on Rails - Railsconf 2014
 
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
Full-Text Search Explained - Philipp Krenn - Codemotion Rome 2017
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
 
Copy/paste detector for source code on javascript
Copy/paste detector for source code on javascript Copy/paste detector for source code on javascript
Copy/paste detector for source code on javascript
 
Ams adapters
Ams adaptersAms adapters
Ams adapters
 
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B) Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
 
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
APIdays Zurich 2019 - Specification Driven Development for REST APIS Alexande...
 
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
APIdays Helsinki 2019 - Specification-Driven Development of REST APIs with Al...
 
GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za mało
 
WIRED and the WP REST API
WIRED and the WP REST APIWIRED and the WP REST API
WIRED and the WP REST API
 
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
Liferay Search: Best Practices to Dramatically Improve Relevance - Liferay Sy...
 
Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk   Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk
 
Real-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @MoldcampReal-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @Moldcamp
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInauts
 
Agile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collectionAgile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collection
 
Elasticsearch in 15 Minutes
Elasticsearch in 15 MinutesElasticsearch in 15 Minutes
Elasticsearch in 15 Minutes
 
Elasticsearch in 15 minutes
Elasticsearch in 15 minutesElasticsearch in 15 minutes
Elasticsearch in 15 minutes
 
Elasticsearch intro output
Elasticsearch intro outputElasticsearch intro output
Elasticsearch intro output
 

More from Pokai Chang

Colorgy - 校園 Open API 平台
Colorgy - 校園 Open API 平台Colorgy - 校園 Open API 平台
Colorgy - 校園 Open API 平台
Pokai Chang
 
Git 實務圖解
Git 實務圖解Git 實務圖解
Git 實務圖解
Pokai Chang
 
Intensive Wireless Communications Engineering: Current Practices (Instructor ...
Intensive Wireless Communications Engineering: Current Practices (Instructor ...Intensive Wireless Communications Engineering: Current Practices (Instructor ...
Intensive Wireless Communications Engineering: Current Practices (Instructor ...Pokai Chang
 
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
Pokai Chang
 
WCET 認證與培訓計畫說明 by 鄭瑞光教授
WCET 認證與培訓計畫說明 by 鄭瑞光教授WCET 認證與培訓計畫說明 by 鄭瑞光教授
WCET 認證與培訓計畫說明 by 鄭瑞光教授
Pokai Chang
 
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
Pokai Chang
 

More from Pokai Chang (6)

Colorgy - 校園 Open API 平台
Colorgy - 校園 Open API 平台Colorgy - 校園 Open API 平台
Colorgy - 校園 Open API 平台
 
Git 實務圖解
Git 實務圖解Git 實務圖解
Git 實務圖解
 
Intensive Wireless Communications Engineering: Current Practices (Instructor ...
Intensive Wireless Communications Engineering: Current Practices (Instructor ...Intensive Wireless Communications Engineering: Current Practices (Instructor ...
Intensive Wireless Communications Engineering: Current Practices (Instructor ...
 
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
 
WCET 認證與培訓計畫說明 by 鄭瑞光教授
WCET 認證與培訓計畫說明 by 鄭瑞光教授WCET 認證與培訓計畫說明 by 鄭瑞光教授
WCET 認證與培訓計畫說明 by 鄭瑞光教授
 
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
無線通訊產業之發展趨勢與人才需求 by 經濟部通訊產業發展推動小組 黃建智 經理
 

Recently uploaded

GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
Pierluigi Pugliese
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Vladimir Iglovikov, Ph.D.
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
20 Comprehensive Checklist of Designing and Developing a Website
20 Comprehensive Checklist of Designing and Developing a Website20 Comprehensive Checklist of Designing and Developing a Website
20 Comprehensive Checklist of Designing and Developing a Website
Pixlogix Infotech
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
Octavian Nadolu
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 

Recently uploaded (20)

GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
20 Comprehensive Checklist of Designing and Developing a Website
20 Comprehensive Checklist of Designing and Developing a Website20 Comprehensive Checklist of Designing and Developing a Website
20 Comprehensive Checklist of Designing and Developing a Website
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 

GraphQL & Relay - 串起前後端世界的橋樑

  • 2. Q: 這個 app 需要多少 API Endpoints?
  • 3. Ans: 4 GET /api/todos.json POST /api/todos.json PATCH /api/todos/id.json DELETE /api/todos/id.json
  • 4. Q: 那這個 app 需要多少 API Endpoints 呢?
  • 9. Q: 那這個 app 需要多少 API Endpoints 呢?
  • 12. $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name": "Lucy", "bio":"...", "followers": [◌], "repos": [◌, ◌]
 } $ { "name": "Ja "bio":"..." "followers" "repos": [◌ } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Hello World", "description": "...", "stargazers": [◌, ◌]
 } ! { "name": "Handy Ut "description": ". "stargazers": [◌] } ! { "name": "Awes "description" "stargazers": } ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { } { "viewer": ◌
 } GraphQL
  • 13. $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name": "Lucy", "bio":"...", "followers": [◌], "repos": [◌, ◌]
 } $ { "name": "Ja "bio":"..." "followers" "repos": [◌ } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Hello World", "description": "...", "stargazers": [◌, ◌]
 } ! { "name": "Handy Ut "description": ". "stargazers": [◌] } ! { "name": "Awes "description" "stargazers": } ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { } { "viewer": ◌
 }
  • 14. $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } $ { "name" "bio": "follo "repos } ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! { } { "viewer": ◌
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ dd dd dd dd
  • 15. ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } { } { "viewer": ◌
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name" "bio": "follo "repos } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } $ $ $ $ $ $
  • 16. ! ! { "name": "Thi "description "stargazers" } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } { } { "viewer": ◌
 } $ $ $ $ $ $ $ $ $ $ $ / $ { "name" "bio": "follo "repos } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 }
  • 17. ⬡ GraphQL 簡介 ⬡ Relay ⼿手感評測 ⬡ Relay 基本使⽤用 ⬡ 全端案例例:GraphQL & Relay on Rails
 https://github.com/zetavg/RailsRelayTodoMVC 不會講到跟 Apollo 的比較 Outline
  • 18. ⬡ GraphQL 簡介 ⬡ Relay ⼿手感評測 ⬡ Relay 基本使⽤用 ⬡ 全端案例例:GraphQL & Relay on Rails
 https://github.com/zetavg/RailsRelayTodoMVC 不會講到跟 Apollo 的比較 Outline
  • 19. 基本查詢 ⬢ 最外層⼀一定是 query ⬢ 問什什麼得什什麼 { "data": { "viewer": { "name": "Pokai Chang" } } } query { viewer { name } }
  • 20. 查詢更更多 ⬢ 巢狀狀選取欄欄位 (field) { "data": { "viewer": { "name": "Pokai Chang", "birthday": { "month": 7, "day": 2 } } } } query { viewer { name birthday { month day } } }
  • 21. 巢狀狀查更更多 ⬢ 底下的資料 (node) 可能是同⼀一種類型 (type) { "data": { "viewer": { "name": "Pokai Chang", "following": [ { "name": "..." }, { "name": "..." }, { "name": "..." } ] } } } query { viewer { name following { name } } }
  • 22. 巢狀狀查更更多多多多 ⬢ 可以幹奇怪的事⋯⋯ { "data": { "viewer": { "name": "Pokai Chang", "following": [ { "name": "…", "followers": [ { "name": "Pokai Chang", "following": [ { "name": "…", "followers": [ { "name": "Pokai C query { viewer { name following { name followers { following { name followers { name } } } } } }
  • 23. 型別定義即⽂文件 query { viewer { name birthday { month day } following { name } } } type Query { viewer: User } type User { name: String birthday: Date followers: [User] following: [User] } type Date { year: Integer month: Integer day: Integer }
  • 24. $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name": "Lucy", "bio":"...", "followers": [◌], "repos": [◌, ◌]
 } $ { "name": "Ja "bio":"..." "followers" "repos": [◌ } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Hello World", "description": "...", "stargazers": [◌, ◌]
 } ! { "name": "Handy Ut "description": ". "stargazers": [◌] } ! { "name": "Awes "description" "stargazers": } ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { } { "viewer": ◌
 }
  • 25. $ { "name" "bio": "follo "repos } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } { } { "viewer": ◌
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } query { viewer { name bio } }
  • 26. ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } { } { "viewer": ◌
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name" "bio": "follo "repos } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } query { viewer { name bio followers { name } } }
  • 27. ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } $ { "name" "bio": "follo "repos } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! { } { "viewer": ◌
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } query { viewer { name bio followers { name } repos { name stargazers { name } } } }
  • 28. { } { "viewer": ◌
 } ! ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name" "bio": "follo "repos } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Thi "description "stargazers" } ! query { viewer { name bio followers { name } repos { name stargazers { name } } girlfriend { name } } } '
  • 29. query { viewer { name bio followers { name } repos { name stargazers { name } } girlfriend { name } } } { "errors": [ { "message": "Field 'girlfriend' doesn't
 exist on type ‘User’", ... } ] } '
  • 30. Arguments 參參數 ⬢ 每個 field 會定義可⽤用的參參數 query { user(id: 1) { name } }
  • 31. Arguments 參參數 ⬢ 也可以做巢狀狀查詢 query { user(id: 1) { name repo(name: "awesome-graphql") { name description } } }
  • 32. Fragment 片段 fragment profileFields on User { name bio avatarUrl } query { viewer { ...profileFields } user(id: 1) { ...profileFields } } 先把固定會⽤用到的欄欄位 存成有意義的片段
  • 33. 改資料 ? Mutation ⬢ query 改成 mutation,data 放在 arguments ⬢ 其實就像 HTTP GET/POST,只是慣例例,沒有硬性限制 mutation { addComment(input: { subjectId: 1, body: "Hi." }) { subject { comments { body } } } }
  • 35. ⬡ GraphQL 簡介 ⬡ Relay ⼿手感評測 ⬡ Relay 基本使⽤用 ⬡ 全端案例例:GraphQL & Relay on Rails
 https://github.com/zetavg/RailsRelayTodoMVC 不會講到跟 Apollo 的比較 Outline
  • 36. 無限捲軸 Caching Prefetch Caching Server Data Updating Optimistic Update Realtime Update
  • 39.
  • 40. const View = (data) => UI
  • 46. $ { "name": "Neson", "bio":"Yet another geek.", "followers": [◌, ◌, ◌], "repos": [◌, ◌, ◌]
 } $ { "name": "Lucy", "bio":"...", "followers": [◌], "repos": [◌, ◌]
 } $ { "name": "Ja "bio":"..." "followers" "repos": [◌ } $ { "name": "Pusheen", "bio":"Nyan nyan nyan~", "followers": [◌], "repos": [◌]
 } ! { "name": "Thing Compiler", "description": "...", "stargazers": [◌, ◌, ◌]
 } ! { "name": "Hello World", "description": "...", "stargazers": [◌, ◌]
 } ! { "name": "Handy Ut "description": ". "stargazers": [◌] } ! { "name": "Awes "description" "stargazers": } ! { "name": "Todo", "description": "...", "stargazers": [◌]
 } ! { } { "viewer": ◌
 } GraphQL
  • 47. Relay 的狀狀況 View $ $ $ $ $ dd $ $ $ $ dd dd dd Relay Store
  • 48. Relay 的狀狀況 View $ $ $ $ dd $ $ $ $ dd dd dd Relay Store viewer { name bio } $ Backend query { viewer { name bio } } { "data": { "viewer": { "name": "…", "Bio": "…" } } }
  • 49. Relay 的狀狀況 View ㄎㄎㄎㄎ$ $ $ $ dd $ $ $ $ dd dd dd Relay Store viewer { name bio } $
  • 50. Relay 的狀狀況 View ㄎㄎㄎㄎ dd dd dd dd $ $ $ $ $ $ $ viewer { name bio } $ $ viewer { followers { name } } Backend query { viewer { followers { name } } } { "data": { "viewer": { "followers": […] } } } Relay Store Request only the diff!
  • 51. Relay 的狀狀況 View ㄎㄎㄎㄎ dd dd dd dd $ $ $ $ $ $ $ viewer { name bio } $ $ viewer { followers { name } }
  • 52. Relay 的狀狀況 viewer { name bio } View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ viewer { followers { name } } dd dd dd dd viewer { repos { name description } } Backend query { viewer { repos { name description } } } { "data": { "viewer": { "repos": […] } } }
  • 53. Relay 的狀狀況 viewer { name bio } View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ viewer { followers { name } } dd dd dd dd viewer { repos { name description } }
  • 54. Relay 的狀狀況 View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ dd dd dd dd RenameRepoMutation( repoID: "…", name: "" )
  • 55. Relay 的狀狀況 View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ dd dd dd dd RenameRepoMutation( repoID: "…", name: "" ) Optimistic Updater
  • 56. Relay 的狀狀況 View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ dd dd dd dd RenameRepoMutation( repoID: "…", name: "" ) Optimistic UpdaterBackend Updater
  • 57. Relay 的狀狀況 View $ ㄎㄎㄎㄎ$ $ $ $ $ $ $ $ dd dd dd dd RenameRepoMutation( repoID: "…", name: "" ) Optimistic UpdaterBackend Updater
  • 58. 想分⾴頁 ? Connections ⬢ 游標分⾴頁法:Relay Cursor Connections query { viewer { friends(first: 10, after: "someCursor") { edges { cursor node { id name } } pageInfo { hasNextPage } } } } Edge (UserEdgeType) Node (UserType) { … } Cursor 游標 Connection Edges Edge (UserEdgeType) Node (UserType) { … } Cursor Edge (UserEdgeTy Node (UserType { … } Cursor Page Info 起始游標
  • 59. ⬢ Offset based pagination ⬢ Cursor based pagination Why Cursor? page 1 page 2 page 1 page 2 page 3 page 3 ' 壞ㄌ next 5next 5
  • 60. ⬡ Relay 可信的 Optimistic Updater 機制可以做 「連線問題時重試」甚⾄至離線更更動上線後同步 ⬡ Relay 的 backend 不⼀一定要是 server,也許可以 是裝置上的 database ⬡ 再狂⼀一點,也許我們還能透過⾃自⼰己實作 Relay RecordSource 組出這樣的架構: Fun Things to Try RelayRelay ViewServer Client DB Memory
  • 62.
  • 63.
  • 64.
  • 65.
  • 67. 適⽤用情況 ⬢ Data driven,data 越多越雜,投資越划算 ⬢ React app ⬢ 略略懂後端 ⬢ 踩雷的勇氣 Relay Environment Handler Provider Network Layer Store Record Source GraphQL Endpoint Query Renderer Container Component Fragment Query
  • 69. ⬡ GraphQL 簡介 ⬡ Relay ⼿手感評測 ⬡ Relay 基本使⽤用 ⬡ 全端案例例:GraphQL & Relay on Rails
 https://github.com/zetavg/RailsRelayTodoMVC 不會講到跟 Apollo 的比較 Outline
  • 70. 在 React 專案中安裝 Relay $ yarn add react-relay
  • 71. 安裝 GraphQL 語法識別外掛 $ yarn add --dev babel-plugin-relay
  • 72. 記得⼿手動加 Babel Plugin ⬢ 編輯 .eslintrc 或 package.json "plugins": [ "relay", ]
  • 73. 安裝 Relay GraphQL 編譯器 $ yarn add --dev relay-compiler
  • 74. 使⽤用 relay-compiler ⬢ 在 JavaScript 裡寫的 GraphQL 需要被事先編譯⋯⋯
 
 ⬢ 改了了 graphql`…` tag 裡⾯面的內容後都要跑⼀一次 ⬢ 或是加上 --watch 參參數監看變化 $ relay-compiler --src ./src --schema ./schema.graphql 源碼⽬目錄 GraphQL Schema 檔位置
  • 75. import { Environment } from ‘relay-runtime’ const environment = new Environment({ network, store, }) export default environment 環境準備 Relay Environment Handler Provider Network Layer Store Record Source GraphQL Endpoint Network Layer Store ⬢ 先看整個環境⋯⋯
  • 76. import { Network } from ‘relay-runtime' const API_ENDPOINT = 'https://api.github.com/graphql' const fetchQuery = (operation, variables) => { return fetch(API_ENDPOINT, { method: 'POST', body: JSON.stringify({ query: operation.text, variables, }), }).then(response => response.json()) } const network = Network.create(fetchQuery) exports default network Relay 網路路層 ⬢ 給⼀一個溝通介⾯面,⼀一般就是包裝 fetch Relay Environment Handler Provider Network Layer Store Record Source GraphQL Endpoint
  • 77. import { RecordSource, Store, } from 'relay-runtime' const source = new RecordSource() const store = new Store(source) export default store Relay 倉儲 Relay Environment Handler Provider Network Layer Store Record Source GraphQL Endpoint ⬢ Relay 內建具備 garbage collection 的 in-memory record source
  • 79. const MyProfile = () => ( <QueryRenderer environment={environment} query={graphql` query MyProfileQuery { viewer { name } } `} render={({ error, props }) => { if (error) { return <Text>{error.message}</Text> } else if (props) { return <Text>Hello, {props.viewer.name}!</Text> } return <Text>Loading...</Text> }} /> ) 基本招 QueryRenderer 可以設計載入中假畫⾯面 注意名字有規定⽤用 "[檔案名稱]Query" Relay Environment Handler Provider Network Layer Store Record Source GraphQL Endpoint Query Renderer Component Query
  • 80. const UserProfileComponent = ({ user }) => ( <Text>Hello, {user.name}!</Text> ) const UserProfile = createFragmentContainer( UserProfileComponent, graphql` fragment UserProfile_user on User { name login avatarUrl } `, ) export default UserProfile 拆元件 FragmentContainer 注意名字也有規定⽤用 "[檔案名稱]_[prop 名稱]" Relay Environment Store Query Renderer Container Component Fragment Query
  • 81. 拆元件 FragmentContainer 直接引⽤用定義在 Container 裡的 Fragment Relay Environment Store Query Renderer Container Component Fragment Query import MyProfile from '...' const MyProfile = () => ( <QueryRenderer environment={environment} query={graphql` query MyProfileQuery { viewer { ...UserProfile_user } } `} render={({ error, props }) => { if (error) { return <Text>{error.message}</Text> } else if (props) { return <MyProfile user={props.viewer} /> } return <Text>Loading...</Text> }} /> )
  • 82. Component Tree 層層疊疊 Query Renderer Container Fragment Query ContainerContainer Component Component FragmentFragment const UserProfileComponent = ({ user }) => ( <View> <UserName user={user} /> <UserBio user={user} /> </View> ) const UserProfile = createFragmentContainer( UserProfileComponent, graphql` fragment UserProfile_user on User { ...UserName_user ...UserBio_user } `, ) const UserNameComponent = ({ user }) => ( <Text>Hello, {user.name}!</Text> ) const UserName = createFragmentContainer( UserNameComponent, graphql` fragment UserName_user on User { name avatarUrl } `, ) const UserBioComponent = ({ user }) => ( <Text>{user.bio}</Text> ) const UserBio = createFragmentContainer( UserBioComponent, graphql` fragment UserBio_user on User { bio } `, )
  • 83. 特種 Container ⬢ RefetchContainer ⬡ 提供 instance method 可以改⽤用不同 arguments 索取資料 ⬢ PaginationContainer ⬡ RefetchContainer 進化版 ⬡ ⽤用 Relay Connection 做分⾴頁專⽤用 ⬡ 可以做出 loadMore()、refresh() 等 method 給無限捲軸和 pull to refresh 使⽤用
  • 84. Mutation const mutation = graphql` mutation AddCommentMutation( $input: AddCommentInput! ) { addComment(input: $input) { clientMutationId commentEdge { cursor node { id body } } subject { id commentsCount } } } ` let variables = { input: { subjectId: "aGVsbG8=", body: "Hello Relay", } } commitMutation( environment, { mutation, variables, onCompleted: (response) => { console.log('Success!') }, onError: (err) => { console.error(err) }, }, ) 1 2 3 1 2 3 ⼀一樣有命名規定 宣告 $input 變數以及型別,內容可以在使⽤用時再指定 與 query ⼀一樣列列出欄欄位,這裡需要列列出所有 mutation 執⾏行行後會變更更或新增的資料 2
  • 85. ⬢ 還有需要做的事⋯⋯ Mutation Updater const mutation = graphql` mutation AddCommentMutation( $input: AddCommentInput! ) { addComment(input: $input) { clientMutationId commentEdge { cursor node { id body } } subject { id commentsCount } } } ` Mutation 執⾏行行後,我們需要把新的 edge 安插到
 某個 subject 底下的 comments connection 若若在 payload root 發現具有 id 的 node,
 Relay 慣例例會幫我們更更新好 store 中相應的 node
  • 86. Mutation Updater commitMutation( environment, { mutation, variables: { ... }, updater: (store) => { const payload = store.getRootField('addComment') const newEdge = payload.getLinkedRecord('commentEdge') const subject = payload.getLinkedRecord('subject') const conn = ConnectionHandler.getConnection(subject, ‘commentsConnection') ConnectionHandler.insertEdgeAfter(conn, newEdge) }, optimisticUpdater: (store) => { … }, }, ) 可⾃自訂 store 的 update ⽅方式
  • 87. Mutation Updater ConnectionHandler.insertEdgeAfter(conn, newEdge) }, optimisticUpdater: (store) => { const subject = store.get(subjectID) const newCommentID = `client:newComment:${tempID++}` const newNode = store.create(newCommentID, 'Comment') newNode.setValue(newCommentID, 'id') newNode.setValue(variables.input.body, 'body') const newEdge = store.create( `client:newCommentEdge:${tempID++}`, 'TodoItemEdge', ) newEdge.setLinkedRecord(newNode, 'node') const conn = ConnectionHandler.getConnection(subject, 'commentsConnection') ConnectionHandler.insertEdgeAfter(conn, newEdge) subject.setValue( subject.getValue('commentsCount') + 1, 'commentsCount', ) }, }, ) 製作出暫時的 node 製作出暫時的 edge 把暫時的 edge 安插進 connection ⼿手動更更新計數器
  • 88. ⬡ GraphQL 簡介 ⬡ Relay ⼿手感評測 ⬡ Relay 基本使⽤用 ⬡ 全端案例例:GraphQL & Relay on Rails
 https://github.com/zetavg/RailsRelayTodoMVC 不會講到跟 Apollo 的比較 Outline
  • 89. (GraphQL + Relay) on Rails
  • 90. (GraphQL + Relay) on Rails 全端⼀一天可以寫完,拿來來做 RN 更更顯神⼒力力
  • 91. (GraphQL + Relay) on Rails Debug 省下的時間可以拿來來調各種 1px