├── .eslintignore
├── .gitignore
├── assets
├── codes
│ ├── graphql-query.example
│ ├── graphql-response.example
│ ├── graphql-schema.example
│ ├── min-query.example
│ ├── cache.example
│ ├── fake.example
│ ├── relay-simple-schema.example
│ └── relay-simple.example
├── ctlin.jpg
├── fake.png
├── logos.png
├── relay.png
├── graphiql.png
├── graphql.png
├── masking.png
├── rnplay.png
├── container.png
├── rnplay-app.png
├── react-native.png
├── relay.svg
└── graphql.svg
├── .babelrc
├── dist
├── 044b5116eb37c9646d7af104e2b4a834.jpg
├── 17509a9b39e1232b9a519703901916d2.png
├── 3b2ccdea43ce740aa92b6965c7d72589.png
├── 72299e9b80aef40368b0a3df96de2e46.png
├── 7db7978f9c01dfcde05ac3179ffe8903.png
└── d0054443c53264e7074d92bd297c01c3.png
├── index.js
├── .editorconfig
├── .eslintrc
├── README.md
├── server.js
├── index.html
├── LICENSE
├── webpack.config.production.js
├── webpack.config.js
├── package.json
└── presentation
└── index.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 |
--------------------------------------------------------------------------------
/assets/codes/graphql-query.example:
--------------------------------------------------------------------------------
1 | {
2 | user(id: "chentsulin") {
3 | name
4 | }
5 | }
6 |
7 |
8 |
--------------------------------------------------------------------------------
/assets/ctlin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/ctlin.jpg
--------------------------------------------------------------------------------
/assets/fake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/fake.png
--------------------------------------------------------------------------------
/assets/logos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/logos.png
--------------------------------------------------------------------------------
/assets/relay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/relay.png
--------------------------------------------------------------------------------
/assets/graphiql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/graphiql.png
--------------------------------------------------------------------------------
/assets/graphql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/graphql.png
--------------------------------------------------------------------------------
/assets/masking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/masking.png
--------------------------------------------------------------------------------
/assets/rnplay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/rnplay.png
--------------------------------------------------------------------------------
/assets/container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/container.png
--------------------------------------------------------------------------------
/assets/rnplay-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/rnplay-app.png
--------------------------------------------------------------------------------
/assets/codes/graphql-response.example:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "user": {
4 | "name": "C.T.Lin"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/assets/react-native.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/assets/react-native.png
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react", "stage-0"],
3 | "env": {
4 | "development": {
5 | "presets": ["react-hmre"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/dist/044b5116eb37c9646d7af104e2b4a834.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/044b5116eb37c9646d7af104e2b4a834.jpg
--------------------------------------------------------------------------------
/dist/17509a9b39e1232b9a519703901916d2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/17509a9b39e1232b9a519703901916d2.png
--------------------------------------------------------------------------------
/dist/3b2ccdea43ce740aa92b6965c7d72589.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/3b2ccdea43ce740aa92b6965c7d72589.png
--------------------------------------------------------------------------------
/dist/72299e9b80aef40368b0a3df96de2e46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/72299e9b80aef40368b0a3df96de2e46.png
--------------------------------------------------------------------------------
/dist/7db7978f9c01dfcde05ac3179ffe8903.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/7db7978f9c01dfcde05ac3179ffe8903.png
--------------------------------------------------------------------------------
/dist/d0054443c53264e7074d92bd297c01c3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chentsulin/modernweb2016-graphql-relay-intro/HEAD/dist/d0054443c53264e7074d92bd297c01c3.png
--------------------------------------------------------------------------------
/assets/codes/graphql-schema.example:
--------------------------------------------------------------------------------
1 | type User {
2 | id: String
3 | email: String
4 | name: String
5 | friends: [User]
6 | }
7 |
8 | type Query {
9 | user(id: String!): User
10 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "react-dom";
3 |
4 | import Presentation from "./presentation";
5 |
6 | render(, document.getElementById("root"));
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | trim_trailing_whitespace = true
7 | insert_final_newline = true
8 |
9 | [*.example]
10 | insert_final_newline = false
11 |
12 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ---
2 | "extends":
3 | - "eslint-config-defaults/configurations/walmart/es6-react"
4 |
5 | "rules":
6 | "indent": [2, 2, {"SwitchCase": 1}]
7 | "max-len": 0
8 |
9 | "env":
10 | "browser": true,
11 | "node": true
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # modernweb2016-graphql-relay-intro
2 |
3 | [https://chentsulin.github.io/modernweb2016-graphql-relay-intro](https://chentsulin.github.io/modernweb2016-graphql-relay-intro)
4 |
5 | Slides for [Modern Web Conference 2016](http://modernweb.tw/) talk - Data Fetching 的過去與未來 - from REST to GraphQL + Relay
6 |
--------------------------------------------------------------------------------
/assets/codes/min-query.example:
--------------------------------------------------------------------------------
1 | // REST
2 | fetch('/posts')
3 | .then(parseJSON)
4 | .then(posts => Promise.all(
5 | posts.map(
6 | post => fetch(post.href)
7 | .then(parseJSON)
8 | )
9 | ))
10 | .then(posts => { ... });
11 |
12 | // GraphQL
13 | graphql.get(
14 | `query { posts { id, title, content } }`
15 | )
16 | .then(posts => { ...});
--------------------------------------------------------------------------------
/assets/codes/cache.example:
--------------------------------------------------------------------------------
1 | Map {
2 | // `story(id: "1")`
3 | 1: Map {
4 | author: Link(2),
5 | comments: [Link(3)],
6 | },
7 | // `story.author`
8 | 2: Map {
9 | name: 'Yuzhi',
10 | photo: 'http://.../photo1.jpg',
11 | },
12 | // `story.comments[0]`
13 | 3: Map {
14 | author: Link(2),
15 | },
16 | }
--------------------------------------------------------------------------------
/assets/codes/fake.example:
--------------------------------------------------------------------------------
1 | {
2 | post(id: 1234) {
3 | content, photo, createdAt,
4 | postedBy { name, profilePic }
5 | likers {
6 | edges {
7 | node { ...user }
8 | }
9 | }
10 | comments {
11 | edges {
12 | node {
13 | text
14 | postedBy { ...user }
15 | replies { ... }
16 | createdAt
17 | }
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var express = require("express");
5 | var webpack = require("webpack");
6 | var config = require("./webpack.config");
7 |
8 | var app = express();
9 | var compiler = webpack(config);
10 |
11 | var serverPort = process.env.PORT || 3000;
12 |
13 | app.use(require("webpack-dev-middleware")(compiler, {
14 | noInfo: true,
15 | publicPath: config.output.publicPath
16 | }));
17 |
18 | app.use(require("webpack-hot-middleware")(compiler));
19 |
20 | app.get("*", function(req, res) {
21 | res.sendFile(path.join(__dirname, "index.html"));
22 | });
23 |
24 | app.listen(serverPort, "localhost", function (err) {
25 | if (err) {
26 | console.log(err);
27 | return;
28 | }
29 |
30 | console.log("Listening at http://localhost:" + serverPort);
31 | });
32 |
--------------------------------------------------------------------------------
/assets/relay.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Modern Web 2016 Graphql Relay Intro @ chentsulin
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/assets/codes/relay-simple-schema.example:
--------------------------------------------------------------------------------
1 | /* Copy from https://facebook.github.io/relay/ */
2 | import {
3 | GraphQLInt,
4 | GraphQLList,
5 | GraphQLObjectType,
6 | GraphQLSchema,
7 | GraphQLString,
8 | } from 'graphql';
9 |
10 | const STORE = {
11 | teas: [
12 | {name: 'Earl Grey Blue Star', steepingTime: 5},
13 | {name: 'Milk Oolong', steepingTime: 3},
14 | {name: 'Gunpowder Golden Temple', steepingTime: 3},
15 | ],
16 | };
17 |
18 | var TeaType = new GraphQLObjectType({
19 | name: 'Tea',
20 | fields: () => ({
21 | name: {type: GraphQLString},
22 | steepingTime: {type: GraphQLInt},
23 | }),
24 | });
25 |
26 | var StoreType = new GraphQLObjectType({
27 | name: 'Store',
28 | fields: () => ({
29 | teas: {type: new GraphQLList(TeaType)},
30 | }),
31 | });
32 |
33 | export default new GraphQLSchema({
34 | query: new GraphQLObjectType({
35 | name: 'Query',
36 | fields: () => ({
37 | store: {
38 | type: StoreType,
39 | resolve: () => STORE,
40 | },
41 | }),
42 | }),
43 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/webpack.config.production.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var webpack = require("webpack");
5 |
6 | module.exports = {
7 | entry: [
8 | "babel-polyfill",
9 | "./index"
10 | ],
11 | output: {
12 | path: path.join(__dirname, "dist"),
13 | filename: "bundle.js",
14 | publicPath: "/dist/"
15 | },
16 | plugins: [
17 | new webpack.optimize.OccurenceOrderPlugin(),
18 | new webpack.DefinePlugin({
19 | "process.env": {
20 | "NODE_ENV": JSON.stringify("production")
21 | }
22 | }),
23 | new webpack.optimize.UglifyJsPlugin({
24 | compressor: {
25 | warnings: false
26 | }
27 | })
28 | ],
29 | module: {
30 | loaders: [{
31 | test: /\.md$/,
32 | loader: "html-loader!markdown-loader?gfm=false"
33 | }, {
34 | test: /\.(js|jsx)$/,
35 | exclude: /node_modules/,
36 | loader: "babel-loader",
37 | query: {
38 | presets: ['es2015', 'react']
39 | }
40 | }, {
41 | test: /\.css$/,
42 | loader: "style-loader!css-loader"
43 | }, {
44 | test: /\.(png|jpg|gif)$/,
45 | loader: "url-loader?limit=8192"
46 | }, {
47 | test: /\.svg$/,
48 | loader: "url?limit=10000&mimetype=image/svg+xml"
49 | }]
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/assets/codes/relay-simple.example:
--------------------------------------------------------------------------------
1 | /* Copy from https://facebook.github.io/relay/ */
2 |
3 | class Tea extends React.Component {
4 | render() {
5 | var {name, steepingTime} = this.props.tea;
6 | return (
7 |
8 | {name} ({steepingTime} min)
9 |
10 | );
11 | }
12 | }
13 | Tea = Relay.createContainer(Tea, {
14 | fragments: {
15 | tea: () => Relay.QL`
16 | fragment on Tea {
17 | name,
18 | steepingTime,
19 | }
20 | `,
21 | },
22 | });
23 |
24 | class TeaStore extends React.Component {
25 | render() {
26 | return
27 | {this.props.store.teas.map(
28 | tea =>
29 | )}
30 |
;
31 | }
32 | }
33 | TeaStore = Relay.createContainer(TeaStore, {
34 | fragments: {
35 | store: () => Relay.QL`
36 | fragment on Store {
37 | teas { ${Tea.getFragment('tea')} },
38 | }
39 | `,
40 | },
41 | });
42 |
43 | class TeaHomeRoute extends Relay.Route {
44 | static routeName = 'Home';
45 | static queries = {
46 | store: (Component) => Relay.QL`
47 | query TeaStoreQuery {
48 | store { ${Component.getFragment('store')} },
49 | }
50 | `,
51 | };
52 | }
53 |
54 | ReactDOM.render(
55 | ,
59 | mountNode
60 | );
61 |
62 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var path = require("path");
4 | var webpack = require("webpack");
5 |
6 | module.exports = {
7 | devtool: "source-map",
8 | entry: [
9 | "webpack-hot-middleware/client",
10 | "babel-polyfill",
11 | "./index"
12 | ],
13 | output: {
14 | path: path.join(__dirname, "dist"),
15 | filename: "bundle.js",
16 | publicPath: "/dist/"
17 | },
18 | plugins: [
19 | new webpack.HotModuleReplacementPlugin(),
20 | new webpack.NoErrorsPlugin()
21 | ],
22 | module: {
23 | loaders: [{
24 | test: /\.md$/,
25 | loader: "html-loader!markdown-loader?gfm=false"
26 | }, {
27 | test: /\.(js|jsx)$/,
28 | exclude: /node_modules/,
29 | loader: "babel-loader",
30 | query: {
31 | presets:['react', 'es2015'],
32 | env: {
33 | development: {
34 | plugins: [["react-transform", {
35 | transforms: [{
36 | transform: "react-transform-hmr",
37 | imports: ["react"],
38 | locals: ["module"]
39 | }]
40 | }]]
41 | }
42 | }
43 | }
44 | }, {
45 | test: /\.css$/,
46 | loaders: ["style", "raw"],
47 | include: __dirname
48 | }, {
49 | test: /\.svg$/,
50 | loader: "url?limit=10000&mimetype=image/svg+xml",
51 | include: path.join(__dirname, "assets")
52 | }, {
53 | test: /\.png$/,
54 | loader: "url-loader?mimetype=image/png",
55 | include: path.join(__dirname, "assets")
56 | }, {
57 | test: /\.gif$/,
58 | loader: "url-loader?mimetype=image/gif",
59 | include: path.join(__dirname, "assets")
60 | }, {
61 | test: /\.jpg$/,
62 | loader: "url-loader?mimetype=image/jpg",
63 | include: path.join(__dirname, "assets")
64 | }]
65 | }
66 | };
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "modernweb2016-graphql-relay-intro",
3 | "version": "1.0.1",
4 | "description": "An introduction to graphql & relay",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "clean": "rimraf dist",
8 | "build": "cross-env NODE_ENV=production webpack --config webpack.config.production.js",
9 | "lint": "eslint --ext .js,.jsx .",
10 | "deploy": "npm run clean & npm run build && git add --all && git commit -nm 'deploy' && git push origin gh-pages",
11 | "start": "cross-env NODE_ENV=development node server.js"
12 | },
13 | "author": "",
14 | "license": "MIT",
15 | "dependencies": {
16 | "normalize.css": "3.0.3",
17 | "react": "^0.14.3",
18 | "react-dom": "^0.14.3",
19 | "spectacle": "^1.0.4",
20 | "spectacle-code-slide": "^0.1.10"
21 | },
22 | "devDependencies": {
23 | "autoprefixer-core": "^6.0.1",
24 | "babel-core": "^6.4.0",
25 | "babel-eslint": "^5.0.0-beta6",
26 | "babel-loader": "^6.2.1",
27 | "babel-plugin-react-transform": "^2.0.2",
28 | "babel-polyfill": "^6.3.14",
29 | "babel-preset-es2015": "^6.3.13",
30 | "babel-preset-react": "^6.3.13",
31 | "babel-preset-react-hmre": "^1.0.1",
32 | "babel-preset-stage-0": "^6.3.13",
33 | "cross-env": "^1.0.7",
34 | "css-loader": "^0.23.0",
35 | "eslint": "^1.8.0",
36 | "eslint-config-defaults": "^7.1.1",
37 | "eslint-plugin-filenames": "^0.1.2",
38 | "eslint-plugin-react": "^3.6.3",
39 | "express": "^4.13.3",
40 | "file-loader": "^0.8.4",
41 | "html-loader": "^0.4.0",
42 | "is-buffer": "^1.1.1",
43 | "markdown-loader": "^0.1.7",
44 | "node-libs-browser": "^0.5.3",
45 | "raw-loader": "^0.5.1",
46 | "react-transform-hmr": "^1.0.4",
47 | "rimraf": "^2.4.4",
48 | "style-loader": "^0.13.0",
49 | "surge": "latest",
50 | "url-loader": "^0.5.6",
51 | "webpack": "^1.12.8",
52 | "webpack-dev-middleware": "^1.2.0",
53 | "webpack-hot-middleware": "^2.5.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/assets/graphql.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
72 |
--------------------------------------------------------------------------------
/presentation/index.js:
--------------------------------------------------------------------------------
1 | // Import React
2 | import React from "react";
3 |
4 | // Import Spectacle Core tags
5 | import {
6 | Appear,
7 | CodePane,
8 | Deck,
9 | Fill,
10 | Fit,
11 | Heading,
12 | Image,
13 | Layout,
14 | Link,
15 | ListItem,
16 | List,
17 | Slide,
18 | Spectacle,
19 | Text
20 | } from "spectacle";
21 |
22 | import CodeSlide from "spectacle-code-slide";
23 |
24 | // Import image preloader util
25 | import preloader from "spectacle/lib/utils/preloader";
26 |
27 | // Import theme
28 | import createTheme from "spectacle/lib/themes/default";
29 |
30 | // Require CSS
31 | require("normalize.css");
32 | require("spectacle/lib/themes/default/index.css");
33 |
34 |
35 | const images = {
36 | ctlin: require("../assets/ctlin.jpg"),
37 | logos: require("../assets/logos.png"),
38 | graphiql: require("../assets/graphiql.png"),
39 | fake: require("../assets/fake.png"),
40 | container: require("../assets/container.png"),
41 | masking: require("../assets/masking.png")
42 | };
43 |
44 | preloader(images);
45 |
46 | const theme = createTheme({
47 | primary: "#7688EA"
48 | });
49 |
50 | export default class Presentation extends React.Component {
51 | render() {
52 | return (
53 |
54 |
55 |
56 |
57 | Data Fetching 的過去與未來
58 |
59 |
60 | - from REST to GraphQL + Relay
61 |
62 | @chentsulin
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | C. T. Lin
72 | Engineering Technical Lead@Yoctol
73 |
74 |
75 |
76 | Node, React, GraphQL..
77 |
78 |
79 | chentsulin@github
80 |
81 |
82 | chentsulin@twitter
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | Release
93 |
94 |
95 |
96 |
97 | GraphQL
2015/07
98 |
99 |
100 |
101 |
102 |
103 |
104 | Relay
2015/08
105 |
106 |
107 |
108 |
109 |
110 |
111 | GraphiQL
2015/08
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | REST
121 |
122 |
123 | Method: GET, POST, PUT, DELETE
124 | Path: /resources, /resources/:id
125 | Status Code: 200, 400, 401, 403, 404...
126 |
127 |
128 |
129 |
130 |
131 | Problems with REST
132 |
133 |
134 | Nested releations
135 | Not efficient with bad network
136 | Versioning
137 | Growing amount of api endpoints
138 | Legacy endpoints and fields
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | /posts/:id
151 | /posts/:id/comments
152 | /posts/:id/likers
153 | /users/:id
154 | /comments/:id/replies
155 | /comments/:id/likers
156 |
157 |
Or something like..
158 |
159 | /post-with-comments-and-replies/:id
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | Easy to over-fetching and under-fetching!
169 |
170 |
171 |
172 |
173 |
174 | GraphQL comes in
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | GraphQL
197 |
198 |
199 | From facebook mobile team (newsfeed)
200 | 260 billion requests/day (2015)
201 | Used for 4 years
202 | One schema for all facebook data
203 |
204 |
205 |
206 |
207 | GraphQL Query
208 |
209 |
210 |
211 | Query
212 |
213 |
219 |
220 |
221 |
222 | Response
223 |
224 |
230 |
231 |
232 |
233 |
234 |
235 |
236 | Just like json without values!
237 |
238 |
239 |
240 |
241 |
242 | Single endpoint (usually /graphql)
243 | No more api endpoints!
244 |
245 |
246 |
247 |
248 |
249 | Only fetch what we need
250 |
251 |
252 |
253 |
254 |
255 | Type System
256 |
257 |
258 |
259 |
260 |
261 | Schema
262 |
263 |
269 |
270 |
271 |
272 |
273 | Types
274 |
275 |
276 | Scalar(Int, Float, String, Boolean, ID)
277 | Object
278 | Interface
279 | Union
280 | Enum
281 | InputObject
282 | List
283 | NonNull
284 |
285 |
286 |
287 |
288 |
289 | Future Ecosystem
290 |
291 |
292 | documentation tools
293 | editor plugins
294 | testing tools
295 | linter
296 |
297 |
298 |
299 |
300 |
301 |
302 | GraphiQL
303 |
304 |
305 |
306 |
307 |
308 |
309 | Demo
310 |
311 |
312 |
313 |
314 |
315 |
316 | Relay
317 |
318 |
319 |
320 |
321 |
322 | Container
323 |
324 |
325 |
326 |
327 |
328 |
329 | Co-locate All the things with Component
330 |
331 |
332 | JavaScript
333 | HTML (jsx)
334 | CSS (CSS in JS, CSS Modules..)
335 | Data Requirement (Relay)
336 | Tests (__tests__)
337 |
338 |
339 |
340 |
341 |
342 | Data Masking
343 |
344 |
345 |
346 |
347 |
348 |
349 | Minimize query
350 |
351 |
352 |
353 |
359 |
360 |
361 |
362 | Avoid N+1 Query
363 | Single Network Request
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 | Cache
372 |
373 |
374 |
375 |
381 |
382 |
383 |
384 | Normalize
385 | Immutable
386 | Views subscribe Record IDs
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 | Default Network Layer
395 |
396 |
397 | Fail requests after a 15 second timeout
398 | failed requests are automatically retried twice
399 |
400 |
401 |
402 |
403 |
404 | Works on React Native!
405 |
406 |
407 |
408 |
420 |
421 |
435 |
436 |
437 |
438 | Demo
439 |
440 |
441 |
442 |
443 |
444 | Resources
445 |
446 |
447 |
448 | Awesome GraphQL
449 |
450 |
451 | Let's Learn GraphQL
452 |
453 |
454 | GraphQL Cheat Sheet
455 |
456 |
457 | GraphQL 繁中文件
458 |
459 |
460 | Relay 繁中文件
461 |
462 |
463 |
464 |
465 |
466 |
467 | End
468 |
469 |
470 | Thank you for listening!
471 |
472 |
473 |
474 |
475 | );
476 | }
477 | }
478 |
--------------------------------------------------------------------------------