SlideShare a Scribd company logo
- INTERNAL USE ONLY -
Apollo ecosystem
1
James Akwuh
Frontend Lead @ Marketplace Group
Minsk, July 2018
- INTERNAL USE ONLY -
Agenda
• Preface
• Setup & Examples
• Tooling
• Security
• Versioning
• Monitoring
• Files upload
• Pagination
• Schema design
• ACL
• State management
• Performance
• Testing react components
• Server-side rendering
2
- INTERNAL USE ONLY -
Agenda
• Apollo 2.1
• Relay
• Conclusion
3
- INTERNAL USE ONLY -
Preface
4
- INTERNAL USE ONLY -
Apollo Platform
• Apollo Client (ApolloClient, Query/Mutation/Subscription)
• Apollo Server (ApolloServer, makeExecutableSchema)
• Apollo Engine $$$ (express app gateway)
5
- INTERNAL USE ONLY -
Apollo consumers
• The NY Times
• Airbnb
• Express (ecommerce retailer)
• Major League Soccer
• Expo
• KLM
• Adform!
6
- INTERNAL USE ONLY -
Setup & Examples
7
- INTERNAL USE ONLY -
Apollo Server
8
# schema.graphql
type DealResponse {
count: Int
results: [Deal]
}
type Deal {
id: String
name: String
}
type Query {
deals(
text: String
): DealResponse
}
- INTERNAL USE ONLY -
Apollo Server
9
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import fs from 'fs';
const schemaDefinition = fs.readFileSync('./src/schema/schemaDefinition.gql', 'utf8');
const executableSchema = makeExecutableSchema({
typeDefs: schemaDefinition
});
addMockFunctionsToSchema({
schema: executableSchema
});
export default executableSchema;
- INTERNAL USE ONLY -
Apollo Server
10
app.post(
['/schema', '/graphql'],
bodyParser.json(),
(req, res, next) => {setTimeout(next, 500)},
graphqlExpress({
schema: executableSchema,
tracing: false,
graphiql: true
})
);
- INTERNAL USE ONLY -
Apollo Engine
11
const engine = new ApolloEngine({
apiKey: 'API_KEY_HERE'
});
// Call engine.listen instead of app.listen(port)
engine.listen({
port: 3000,
expressApp: app,
});
- INTERNAL USE ONLY -
Apollo Client
12
import ApolloClient from "apollo-boost";
const ConnectedApp = () => {
const client = new ApolloClient({
uri: "https://w5xlvm3vzz.lp.gql.zone/graphql"
});
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
)
};
- INTERNAL USE ONLY -
Apollo Client
13
client
.query({
query: gql`
{
rates(currency: "USD") {
currency
}
}
`
})
.then(result => console.log(result));
- INTERNAL USE ONLY -
Apollo Query*
14
const GET_DOGS = gql`
{
dogs {
id
breed
}
}
`;
const Dogs = props => (
<Query query={GET_DOGS}>
{({ loading, error, data }) => {
// ...
}}
</Query>
);
- INTERNAL USE ONLY -
Tooling
15
- INTERNAL USE ONLY -
Tooling
• GraphQL Playground / GraphiQL
• launchpad.graphql.com
• Apollo Devtools*
• Apollo Engine
• babel-plugin-import-graphql
• ...
16
- INTERNAL USE ONLY -
Security
17
- INTERNAL USE ONLY -
Security. Schema introspection
“For security, Apollo Server introspection is automatically
disabled when the NODE_ENV is set to production or
testing”
18
- INTERNAL USE ONLY -
Security. Injection
No:
deals(filters="limit=1") {
count
}
Yes:
deals(limit=1) {
count
}
• Doesn’t help with string parameters:
19
- INTERNAL USE ONLY -
Security. DoS
query evil {
album(id: 42) {
songs {
album {
songs {
album {
songs {
album {
songs {
album {
songs {
album {
songs {
album {
# and so on...
}
}
}
}
}
}
}
}
}
}
}
}
}
}
20
- INTERNAL USE ONLY -
Security. DoS
As usual +
- Operation safe-listing
- Complexity limits: simple and advanced
21
- INTERNAL USE ONLY -
Security. DoS
Max Stoiber Advanced security
22
- INTERNAL USE ONLY -
Versioning
23
- INTERNAL USE ONLY -
Versioning
• No API versions (well, you can actually)
• Field usage (Apollo Engine schema history)
• Field rollover (resolver alias + @deprecated)
- Provide developers with the helpful deprecation
message referring them to the new name.
- Avoid auto-completing the field.
• Changing arguments (no good ideas, use field rollover).
24
- INTERNAL USE ONLY -
Versioning
25
- INTERNAL USE ONLY -
Versioning. Resolver alias
const getUserResolver = (root, args, context) => {
context.User.getById(args.id);
};
const resolvers = {
Query: {
getUser: getUserResolver,
user: getUserResolver,
},
};
26
- INTERNAL USE ONLY -
Versioning. @deprecated
type Query {
user(id: ID!): User @deprecated(reason: "renamed to 'getUser'")
getUser(id: ID!): User
}
27
- INTERNAL USE ONLY -
Versioning. Client fields renaming
query SuggestPublishers($limit: Int, $offset: Int, $text: String) {
items: inventorySources(limit: $limit, offset: $offset, text: $text) {
count
results {
id,
name
}
}
28
- INTERNAL USE ONLY -
Monitoring
29
- INTERNAL USE ONLY -
Monitoring
30
- INTERNAL USE ONLY -
Monitoring
31
- INTERNAL USE ONLY -
Monitoring
32
- INTERNAL USE ONLY -
Monitoring
33
- INTERNAL USE ONLY -
Files Upload
34
- INTERNAL USE ONLY -
Files upload. Server
const resolvers = {
Upload: GraphQLUpload,
Mutation: {
async singleUpload(parent, { file }) {
const { stream, filename, mimetype, encoding } = await file;
// ...
return { stream, filename, mimetype, encoding };
}
},
};
35
- INTERNAL USE ONLY -
Files upload. Server
• maxFieldSize
• maxFileSize
• maxFiles
36
- INTERNAL USE ONLY -
Files upload. Client
import { createUploadLink } from 'apollo-upload-client'
const link = createUploadLink(/* Options */)
37
- INTERNAL USE ONLY -
Files upload. Client
export default graphql(gql`
mutation($files: [Upload!]!) {
uploadFiles(files: $files) {
id
}
}
`)(({ mutate }) => (
<input type="file" multiple
onChange={({ target: { validity, files } }) =>
validity.valid && mutate({ variables: { files } })
}
/>
))
38
- INTERNAL USE ONLY -
Pagination
39
- INTERNAL USE ONLY -
Pagination
options: ({ queryVariables }) => ({
variables: queryVariables,
notifyOnNetworkStatusChange: true,
fetchPolicy: APOLLO_FETCH_POLICIES.CACHE_AND_NETWORK,
}),
40
- INTERNAL USE ONLY -
Pagination
props: ({
data: {
error,
loading: isLoading,
items: { availableCount, results = [] } = {},
fetchMore,
refetch,
networkStatus,
},
}) => {...}
41
- INTERNAL USE ONLY -
Pagination
const isFirstPage = networkStatus !== APOLLO_NETWORK_STATUSES.FETCH_MORE;
…
return {
...
/**
* `() => refetch()` is *mandatory* in order to prevent event handlers from passing arguments
such as *event*
* to *Apollo* `refetch` function as it treats arguments as variables for GraphQL queries.
* Otherwise, it would lead to errors in `JSON.parse(...)` when trying to parse circular data.
*/
refetch: () => refetch(),
};
42
- INTERNAL USE ONLY -
Pagination
export const APOLLO_NETWORK_STATUSES = {
FETCH_MORE: NetworkStatus.fetchMore,
/**
* networkStatus === ERROR *only* when http status is bad (e.g. 4xx, 5xx)
* however usually you want to handle also errors in resolvers, e.g.
* http status is 200 but response contains `errors` property.
* Consider using Boolean(data.error) instead of (data.networkStatus === ERROR)
*/
ERROR: NetworkStatus.error,
};
43
- INTERNAL USE ONLY -
Pagination. More pitfalls
• 1.x: fetchMore doesn’t trigger rerender on error
44
- INTERNAL USE ONLY -
Pagination. Imperative update
query Feed($type: FeedType!, $offset: Int, $limit: Int) {
currentUser {
login
}
feed(type: $type, offset: $offset, limit: $limit) @connection(key: "feed") {
id
# ...
}
}
…
client.writeData
45
- INTERNAL USE ONLY -
Schema design
46
- INTERNAL USE ONLY -
Schema design
“Design by client needs”
47
- INTERNAL USE ONLY -
Schema design
• Use interfaces
• Use QueryResponse
• Use MutationResponse
• Use input types
• Use your clients style convention (GQL is flexible)
48
- INTERNAL USE ONLY -
Schema design. QueryResponse
type DealResponse {
availableCount: Int
count: Int
results: [Deal]
}
type Query {
deals(
text: String,
...
): DealResponse
}
49
- INTERNAL USE ONLY -
Schema design. MutationResponse
type LikePostMutationResponse implements MutationResponse {
code: String!
success: Boolean!
message: String!
post: Post
user: User
}
50
- INTERNAL USE ONLY -
Schema design. Input types
input PostAndMediaInput {
"A main title for the post"
title: String
"The textual body of the post."
body: String
"A list of URLs to render in the post."
mediaUrls: [String]
}
51
- INTERNAL USE ONLY -
ACL
52
- INTERNAL USE ONLY -
ACL
Available options:
• Delegate to REST API
• Authorization via context
• Authorization via directives
53
- INTERNAL USE ONLY -
ACL. Authorization via context
context: ({ req }) => {
const token = req.headers.authentication || '';
const user = getUser(token);
if (!user) throw new AuthorizationError('you must be logged in');
return { user };
},
54
- INTERNAL USE ONLY -
ACL. Authorization via context
users: (root, args, context) => {
// In this case, we'll pretend there is no data when
// we're not logged in. Another option would be to
// throw an error.
if (!context.user) return [];
return ['bob', 'jake'];
}
55
- INTERNAL USE ONLY -
ACL. Authorization via directives
directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
REVIEWER
USER
}
type User @auth(requires: USER) {
name: String
banned: Boolean @auth(requires: ADMIN)
canPost: Boolean @auth(requires: REVIEWER)
}
56
- INTERNAL USE ONLY -
State management
57
- INTERNAL USE ONLY -
State management
Since Apollo Client supports managing both local and
remote data, you can use the Apollo cache as a single
source of truth for all global state in your application.
58
- INTERNAL USE ONLY -
State management
apollo-link-state
const client = new ApolloClient({
uri: `https://nx9zvp49q7.lp.gql.zone/graphql`,
clientState: {
defaults,
resolvers,
typeDefs
}
});
59
- INTERNAL USE ONLY -
State management. Defaults
initialState → defaults
60
- INTERNAL USE ONLY -
State management. Resolvers
export const resolvers = {
Mutation: {
toggleTodo: (_, variables, { cache, getCacheKey }) => {
const id = getCacheKey({ __typename: 'TodoItem', id: variables.id })
const fragment = gql`
fragment completeTodo on TodoItem {
completed
}
`;
const todo = cache.readFragment({ fragment, id });
const data = { ...todo, completed: !todo.completed };
cache.writeData({ id, data });
return null;
61
- INTERNAL USE ONLY -
State management. Query
{
todos @client {
id
completed
text
}
visibilityFilter @client
}
62
- INTERNAL USE ONLY -
State management
63
- INTERNAL USE ONLY -
Performance
64
- INTERNAL USE ONLY -
Performance
Optimization points:
• Do not send full query to server
• Cache read requests
• Cache entities on client
• Prefetch entities
• Batch requests
65
- INTERNAL USE ONLY -
Performance. Automatic Persisted Queries
66
- INTERNAL USE ONLY -
Performance. Automatic Persisted Queries
curl -g
'http://localhost:9011/graphql?extensions={"persistedQuery":{"version":1,"sha256Hash":"
ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}'
67
- INTERNAL USE ONLY -
Performance. Automatic Persisted Queries
Client: apollo-link-persisted-queries
Server:
const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: {
cache: new InMemoryCache(),
},
});
68
- INTERNAL USE ONLY -
Performance. CDN integration
createPersistedQueryLink({ useGETForHashedQueries: true })
___
type Author @cacheControl(maxAge: 60) {
id: Int
firstName: String
lastName: String
posts: [Post] @cacheControl(maxAge: 180)
}
69
- INTERNAL USE ONLY -
Performance. Client caching
• Data is normalized and cached by default
• Update mutation updates cached automagically
• Create mutation requires manual cache writes
70
- INTERNAL USE ONLY -
Performance. Client caching
<Mutation
mutation={ADD_TODO}
update={(cache, { data: { addTodo } }) => {
const { todos } = cache.readQuery({ query: GET_TODOS });
cache.writeQuery({
query: GET_TODOS,
data: { todos: todos.concat([addTodo]) }
});
}}
>
Variables! (@connection)
71
- INTERNAL USE ONLY -
Performance. Client caching: cacheRedirects
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
book: (_, args, { getCacheKey }) =>
getCacheKey({ __typename: 'Book', id: args.id })
},
},
});
72
- INTERNAL USE ONLY -
Performance. Prefetching
<Component
onMouseOver={() =>
client.query({
query: GET_DOG,
variables: { breed: data.breed }
})
}
/>
73
- INTERNAL USE ONLY -
Performance. Batch requests
import { BatchHttpLink } from "apollo-link-batch-http";
const link = new BatchHttpLink({ uri: "/graphql" });
74
- INTERNAL USE ONLY -
Testing React components
75
- INTERNAL USE ONLY -
Testing React Components
const mocks = [
{
request: {
query: GET_DOG_QUERY,
variables: {
name: 'Buck',
},
},
result: {
data: {
dog: { id: '1', name: 'Buck', breed: 'bulldog' },
},
},
},
];
76
- INTERNAL USE ONLY -
Testing React Components
it('renders without error', () => {
renderer.create(
<MockedProvider mocks={mocks} addTypename={false}>
<Dog name="Buck" />
</MockedProvider>,
);
});
77
- INTERNAL USE ONLY -
Testing React Components: Loading state
By default
78
- INTERNAL USE ONLY -
Testing React Components: Success state
it('should render dog', async () => {
// ...
await wait(0); // wait for nextTick
// ...
});
79
- INTERNAL USE ONLY -
Testing React Components: Error state
const dogMock = {
request: {
query: GET_DOG_QUERY,
variables: { name: 'Buck' },
},
error: new Error('aw shucks'),
};
80
- INTERNAL USE ONLY -
Server-side rendering
81
- INTERNAL USE ONLY -
Server-side rendering
getDataFromTree(App).then(() => {
const content = ReactDOM.renderToString(App);
const initialState = client.extract();
const html = <Html content={content} state={initialState} />;
res.status(200);
res.send(`<!doctype html>n${ReactDOM.renderToStaticMarkup(html)}`);
res.end();
});
82
- INTERNAL USE ONLY -
Server-side rendering
function Html({ content, state }) {
return (
<html>
<body>
<div id="root" dangerouslySetInnerHTML={{ __html: content }} />
<script dangerouslySetInnerHTML={{
__html: `window.__APOLLO_STATE__=${JSON.stringify(state).replace(/</g,
'u003c')};`,
}} />
</body>
</html>
);
}
83
- INTERNAL USE ONLY -
Server-side rendering. Avoid network calls
const client = new ApolloClient({
ssrMode: true,
link: new SchemaLink({ schema }),
cache: new InMemoryCache(),
});
84
- INTERNAL USE ONLY -
Server-side rendering. Skipping queries
const ClientOnlyUser = () => (
<Query query={GET_USER_WITH_ID} ssr={false}>
{({ data }) => <span>I won't be run on the server</span>}
</Query>
);
85
- INTERNAL USE ONLY -
Server-side rendering. Rehydration
const client = new ApolloClient({
cache: new InMemoryCache().restore(window.__APOLLO_STATE__),
link,
});
86
- INTERNAL USE ONLY -
Apollo 2.1
87
- INTERNAL USE ONLY -
Apollo 2.1
<Query> / <Mutation> / <Subscription>
<ApolloConsumer />
Apollo Devtools
88
- INTERNAL USE ONLY -
Relay
89
- INTERNAL USE ONLY -
Relay
https://open.nytimes.com/the-new-york-times-now-on-apollo-
b9a78a5038c
“Relay takes a “bring your own solution” approach to this
problem. In Apollo, SSR is a first-class feature. This is huge
for us.”
90
- INTERNAL USE ONLY -
Conclusion
91
- INTERNAL USE ONLY -
Conclusion
Apollo is a fully-featured open-source* platform
92
- INTERNAL USE ONLY -
Questions?
93

More Related Content

What's hot

Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09
Michelangelo van Dam
 
Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1
Patrycja Wegrzynowicz
 
Second Level Cache in JPA Explained
Second Level Cache in JPA ExplainedSecond Level Cache in JPA Explained
Second Level Cache in JPA Explained
Patrycja Wegrzynowicz
 
PofEAA and SQLAlchemy
PofEAA and SQLAlchemyPofEAA and SQLAlchemy
PofEAA and SQLAlchemy
Inada Naoki
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805
t k
 
Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
CodeOps Technologies LLP
 
Flask patterns
Flask patternsFlask patterns
Flask patterns
it-people
 
Flask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuthFlask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuth
Eueung Mulyana
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
Nate Abele
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) Bridge
José Paumard
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtup
t k
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
Michelangelo van Dam
 
Thinking Beyond ORM in JPA
Thinking Beyond ORM in JPAThinking Beyond ORM in JPA
Thinking Beyond ORM in JPA
Patrycja Wegrzynowicz
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance Issues
Odoo
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6
Technopark
 
Filling the flask
Filling the flaskFilling the flask
Filling the flask
Jason Myers
 
Python and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsPython and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super Tools
Seth Miller
 
Percona toolkit
Percona toolkitPercona toolkit
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
Vic Metcalfe
 
My Top 5 APEX JavaScript API's
My Top 5 APEX JavaScript API'sMy Top 5 APEX JavaScript API's
My Top 5 APEX JavaScript API's
Roel Hartman
 

What's hot (20)

Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09
 
Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1Lazy vs. Eager Loading Strategies in JPA 2.1
Lazy vs. Eager Loading Strategies in JPA 2.1
 
Second Level Cache in JPA Explained
Second Level Cache in JPA ExplainedSecond Level Cache in JPA Explained
Second Level Cache in JPA Explained
 
PofEAA and SQLAlchemy
PofEAA and SQLAlchemyPofEAA and SQLAlchemy
PofEAA and SQLAlchemy
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805
 
Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
 
Flask patterns
Flask patternsFlask patterns
Flask patterns
 
Flask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuthFlask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuth
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) Bridge
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtup
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Thinking Beyond ORM in JPA
Thinking Beyond ORM in JPAThinking Beyond ORM in JPA
Thinking Beyond ORM in JPA
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance Issues
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6
 
Filling the flask
Filling the flaskFilling the flask
Filling the flask
 
Python and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsPython and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super Tools
 
Percona toolkit
Percona toolkitPercona toolkit
Percona toolkit
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
My Top 5 APEX JavaScript API's
My Top 5 APEX JavaScript API'sMy Top 5 APEX JavaScript API's
My Top 5 APEX JavaScript API's
 

Similar to Apollo ecosystem

How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
Ben Lin
 
Web注入+http漏洞等描述
Web注入+http漏洞等描述Web注入+http漏洞等描述
Web注入+http漏洞等描述
fangjiafu
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
dion
 
Iac d.damyanov 4.pptx
Iac d.damyanov 4.pptxIac d.damyanov 4.pptx
Iac d.damyanov 4.pptx
Dimitar Damyanov
 
IR Journal (itscholar.codegency.co.in).pdf
IR Journal (itscholar.codegency.co.in).pdfIR Journal (itscholar.codegency.co.in).pdf
IR Journal (itscholar.codegency.co.in).pdf
RahulRoy130127
 
Reason and GraphQL
Reason and GraphQLReason and GraphQL
Reason and GraphQL
Nikolaus Graf
 
Spring boot
Spring boot Spring boot
Spring boot
Vinay Prajapati
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
Praveen Puglia
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
Pascal Rettig
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
Siarzh Miadzvedzeu
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript
Qiangning Hong
 
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NYPuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
Puppet
 
Diseño y Desarrollo de APIs
Diseño y Desarrollo de APIsDiseño y Desarrollo de APIs
Diseño y Desarrollo de APIs
Raúl Neis
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
Fastly
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
Iván López Martín
 
OSMC 2009 | Icinga by Icinga Team
OSMC 2009 | Icinga by Icinga TeamOSMC 2009 | Icinga by Icinga Team
OSMC 2009 | Icinga by Icinga Team
NETWAYS
 
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
Arun Gupta
 
Catalyst MVC
Catalyst MVCCatalyst MVC
Catalyst MVC
Sheeju Alex
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
Ayush Sharma
 

Similar to Apollo ecosystem (20)

How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Web注入+http漏洞等描述
Web注入+http漏洞等描述Web注入+http漏洞等描述
Web注入+http漏洞等描述
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
Iac d.damyanov 4.pptx
Iac d.damyanov 4.pptxIac d.damyanov 4.pptx
Iac d.damyanov 4.pptx
 
IR Journal (itscholar.codegency.co.in).pdf
IR Journal (itscholar.codegency.co.in).pdfIR Journal (itscholar.codegency.co.in).pdf
IR Journal (itscholar.codegency.co.in).pdf
 
Reason and GraphQL
Reason and GraphQLReason and GraphQL
Reason and GraphQL
 
Spring boot
Spring boot Spring boot
Spring boot
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript
 
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NYPuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
 
Diseño y Desarrollo de APIs
Diseño y Desarrollo de APIsDiseño y Desarrollo de APIs
Diseño y Desarrollo de APIs
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
 
OSMC 2009 | Icinga by Icinga Team
OSMC 2009 | Icinga by Icinga TeamOSMC 2009 | Icinga by Icinga Team
OSMC 2009 | Icinga by Icinga Team
 
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
 
Catalyst MVC
Catalyst MVCCatalyst MVC
Catalyst MVC
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
 

Recently uploaded

AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
Paris Salesforce Developer Group
 
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICSUNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
vmspraneeth
 
Data Driven Maintenance | UReason Webinar
Data Driven Maintenance | UReason WebinarData Driven Maintenance | UReason Webinar
Data Driven Maintenance | UReason Webinar
UReason
 
An Introduction to the Compiler Designss
An Introduction to the Compiler DesignssAn Introduction to the Compiler Designss
An Introduction to the Compiler Designss
ElakkiaU
 
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
ijseajournal
 
Mechatronics material . Mechanical engineering
Mechatronics material . Mechanical engineeringMechatronics material . Mechanical engineering
Mechatronics material . Mechanical engineering
sachin chaurasia
 
Height and depth gauge linear metrology.pdf
Height and depth gauge linear metrology.pdfHeight and depth gauge linear metrology.pdf
Height and depth gauge linear metrology.pdf
q30122000
 
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
nedcocy
 
Digital Twins Computer Networking Paper Presentation.pptx
Digital Twins Computer Networking Paper Presentation.pptxDigital Twins Computer Networking Paper Presentation.pptx
Digital Twins Computer Networking Paper Presentation.pptx
aryanpankaj78
 
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
Gino153088
 
Pressure Relief valve used in flow line to release the over pressure at our d...
Pressure Relief valve used in flow line to release the over pressure at our d...Pressure Relief valve used in flow line to release the over pressure at our d...
Pressure Relief valve used in flow line to release the over pressure at our d...
cannyengineerings
 
Accident detection system project report.pdf
Accident detection system project report.pdfAccident detection system project report.pdf
Accident detection system project report.pdf
Kamal Acharya
 
Mechanical Engineering on AAI Summer Training Report-003.pdf
Mechanical Engineering on AAI Summer Training Report-003.pdfMechanical Engineering on AAI Summer Training Report-003.pdf
Mechanical Engineering on AAI Summer Training Report-003.pdf
21UME003TUSHARDEB
 
ITSM Integration with MuleSoft.pptx
ITSM  Integration with MuleSoft.pptxITSM  Integration with MuleSoft.pptx
ITSM Integration with MuleSoft.pptx
VANDANAMOHANGOUDA
 
Introduction to Computer Networks & OSI MODEL.ppt
Introduction to Computer Networks & OSI MODEL.pptIntroduction to Computer Networks & OSI MODEL.ppt
Introduction to Computer Networks & OSI MODEL.ppt
Dwarkadas J Sanghvi College of Engineering
 
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODELDEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
ijaia
 
2. protection of river banks and bed erosion protection works.ppt
2. protection of river banks and bed erosion protection works.ppt2. protection of river banks and bed erosion protection works.ppt
2. protection of river banks and bed erosion protection works.ppt
abdatawakjira
 
Blood finder application project report (1).pdf
Blood finder application project report (1).pdfBlood finder application project report (1).pdf
Blood finder application project report (1).pdf
Kamal Acharya
 
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
upoux
 
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
sydezfe
 

Recently uploaded (20)

AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
AI + Data Community Tour - Build the Next Generation of Apps with the Einstei...
 
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICSUNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
UNIT 4 LINEAR INTEGRATED CIRCUITS-DIGITAL ICS
 
Data Driven Maintenance | UReason Webinar
Data Driven Maintenance | UReason WebinarData Driven Maintenance | UReason Webinar
Data Driven Maintenance | UReason Webinar
 
An Introduction to the Compiler Designss
An Introduction to the Compiler DesignssAn Introduction to the Compiler Designss
An Introduction to the Compiler Designss
 
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...Call For Paper -3rd International Conference on Artificial Intelligence Advan...
Call For Paper -3rd International Conference on Artificial Intelligence Advan...
 
Mechatronics material . Mechanical engineering
Mechatronics material . Mechanical engineeringMechatronics material . Mechanical engineering
Mechatronics material . Mechanical engineering
 
Height and depth gauge linear metrology.pdf
Height and depth gauge linear metrology.pdfHeight and depth gauge linear metrology.pdf
Height and depth gauge linear metrology.pdf
 
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
一比一原版(爱大毕业证书)爱荷华大学毕业证如何办理
 
Digital Twins Computer Networking Paper Presentation.pptx
Digital Twins Computer Networking Paper Presentation.pptxDigital Twins Computer Networking Paper Presentation.pptx
Digital Twins Computer Networking Paper Presentation.pptx
 
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
4. Mosca vol I -Fisica-Tipler-5ta-Edicion-Vol-1.pdf
 
Pressure Relief valve used in flow line to release the over pressure at our d...
Pressure Relief valve used in flow line to release the over pressure at our d...Pressure Relief valve used in flow line to release the over pressure at our d...
Pressure Relief valve used in flow line to release the over pressure at our d...
 
Accident detection system project report.pdf
Accident detection system project report.pdfAccident detection system project report.pdf
Accident detection system project report.pdf
 
Mechanical Engineering on AAI Summer Training Report-003.pdf
Mechanical Engineering on AAI Summer Training Report-003.pdfMechanical Engineering on AAI Summer Training Report-003.pdf
Mechanical Engineering on AAI Summer Training Report-003.pdf
 
ITSM Integration with MuleSoft.pptx
ITSM  Integration with MuleSoft.pptxITSM  Integration with MuleSoft.pptx
ITSM Integration with MuleSoft.pptx
 
Introduction to Computer Networks & OSI MODEL.ppt
Introduction to Computer Networks & OSI MODEL.pptIntroduction to Computer Networks & OSI MODEL.ppt
Introduction to Computer Networks & OSI MODEL.ppt
 
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODELDEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
DEEP LEARNING FOR SMART GRID INTRUSION DETECTION: A HYBRID CNN-LSTM-BASED MODEL
 
2. protection of river banks and bed erosion protection works.ppt
2. protection of river banks and bed erosion protection works.ppt2. protection of river banks and bed erosion protection works.ppt
2. protection of river banks and bed erosion protection works.ppt
 
Blood finder application project report (1).pdf
Blood finder application project report (1).pdfBlood finder application project report (1).pdf
Blood finder application project report (1).pdf
 
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
一比一原版(uofo毕业证书)美国俄勒冈大学毕业证如何办理
 
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
一比一原版(uoft毕业证书)加拿大多伦多大学毕业证如何办理
 

Apollo ecosystem

  • 1. - INTERNAL USE ONLY - Apollo ecosystem 1 James Akwuh Frontend Lead @ Marketplace Group Minsk, July 2018
  • 2. - INTERNAL USE ONLY - Agenda • Preface • Setup & Examples • Tooling • Security • Versioning • Monitoring • Files upload • Pagination • Schema design • ACL • State management • Performance • Testing react components • Server-side rendering 2
  • 3. - INTERNAL USE ONLY - Agenda • Apollo 2.1 • Relay • Conclusion 3
  • 4. - INTERNAL USE ONLY - Preface 4
  • 5. - INTERNAL USE ONLY - Apollo Platform • Apollo Client (ApolloClient, Query/Mutation/Subscription) • Apollo Server (ApolloServer, makeExecutableSchema) • Apollo Engine $$$ (express app gateway) 5
  • 6. - INTERNAL USE ONLY - Apollo consumers • The NY Times • Airbnb • Express (ecommerce retailer) • Major League Soccer • Expo • KLM • Adform! 6
  • 7. - INTERNAL USE ONLY - Setup & Examples 7
  • 8. - INTERNAL USE ONLY - Apollo Server 8 # schema.graphql type DealResponse { count: Int results: [Deal] } type Deal { id: String name: String } type Query { deals( text: String ): DealResponse }
  • 9. - INTERNAL USE ONLY - Apollo Server 9 import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools'; import fs from 'fs'; const schemaDefinition = fs.readFileSync('./src/schema/schemaDefinition.gql', 'utf8'); const executableSchema = makeExecutableSchema({ typeDefs: schemaDefinition }); addMockFunctionsToSchema({ schema: executableSchema }); export default executableSchema;
  • 10. - INTERNAL USE ONLY - Apollo Server 10 app.post( ['/schema', '/graphql'], bodyParser.json(), (req, res, next) => {setTimeout(next, 500)}, graphqlExpress({ schema: executableSchema, tracing: false, graphiql: true }) );
  • 11. - INTERNAL USE ONLY - Apollo Engine 11 const engine = new ApolloEngine({ apiKey: 'API_KEY_HERE' }); // Call engine.listen instead of app.listen(port) engine.listen({ port: 3000, expressApp: app, });
  • 12. - INTERNAL USE ONLY - Apollo Client 12 import ApolloClient from "apollo-boost"; const ConnectedApp = () => { const client = new ApolloClient({ uri: "https://w5xlvm3vzz.lp.gql.zone/graphql" }); return ( <ApolloProvider client={client}> <App /> </ApolloProvider> ) };
  • 13. - INTERNAL USE ONLY - Apollo Client 13 client .query({ query: gql` { rates(currency: "USD") { currency } } ` }) .then(result => console.log(result));
  • 14. - INTERNAL USE ONLY - Apollo Query* 14 const GET_DOGS = gql` { dogs { id breed } } `; const Dogs = props => ( <Query query={GET_DOGS}> {({ loading, error, data }) => { // ... }} </Query> );
  • 15. - INTERNAL USE ONLY - Tooling 15
  • 16. - INTERNAL USE ONLY - Tooling • GraphQL Playground / GraphiQL • launchpad.graphql.com • Apollo Devtools* • Apollo Engine • babel-plugin-import-graphql • ... 16
  • 17. - INTERNAL USE ONLY - Security 17
  • 18. - INTERNAL USE ONLY - Security. Schema introspection “For security, Apollo Server introspection is automatically disabled when the NODE_ENV is set to production or testing” 18
  • 19. - INTERNAL USE ONLY - Security. Injection No: deals(filters="limit=1") { count } Yes: deals(limit=1) { count } • Doesn’t help with string parameters: 19
  • 20. - INTERNAL USE ONLY - Security. DoS query evil { album(id: 42) { songs { album { songs { album { songs { album { songs { album { songs { album { songs { album { # and so on... } } } } } } } } } } } } } } 20
  • 21. - INTERNAL USE ONLY - Security. DoS As usual + - Operation safe-listing - Complexity limits: simple and advanced 21
  • 22. - INTERNAL USE ONLY - Security. DoS Max Stoiber Advanced security 22
  • 23. - INTERNAL USE ONLY - Versioning 23
  • 24. - INTERNAL USE ONLY - Versioning • No API versions (well, you can actually) • Field usage (Apollo Engine schema history) • Field rollover (resolver alias + @deprecated) - Provide developers with the helpful deprecation message referring them to the new name. - Avoid auto-completing the field. • Changing arguments (no good ideas, use field rollover). 24
  • 25. - INTERNAL USE ONLY - Versioning 25
  • 26. - INTERNAL USE ONLY - Versioning. Resolver alias const getUserResolver = (root, args, context) => { context.User.getById(args.id); }; const resolvers = { Query: { getUser: getUserResolver, user: getUserResolver, }, }; 26
  • 27. - INTERNAL USE ONLY - Versioning. @deprecated type Query { user(id: ID!): User @deprecated(reason: "renamed to 'getUser'") getUser(id: ID!): User } 27
  • 28. - INTERNAL USE ONLY - Versioning. Client fields renaming query SuggestPublishers($limit: Int, $offset: Int, $text: String) { items: inventorySources(limit: $limit, offset: $offset, text: $text) { count results { id, name } } 28
  • 29. - INTERNAL USE ONLY - Monitoring 29
  • 30. - INTERNAL USE ONLY - Monitoring 30
  • 31. - INTERNAL USE ONLY - Monitoring 31
  • 32. - INTERNAL USE ONLY - Monitoring 32
  • 33. - INTERNAL USE ONLY - Monitoring 33
  • 34. - INTERNAL USE ONLY - Files Upload 34
  • 35. - INTERNAL USE ONLY - Files upload. Server const resolvers = { Upload: GraphQLUpload, Mutation: { async singleUpload(parent, { file }) { const { stream, filename, mimetype, encoding } = await file; // ... return { stream, filename, mimetype, encoding }; } }, }; 35
  • 36. - INTERNAL USE ONLY - Files upload. Server • maxFieldSize • maxFileSize • maxFiles 36
  • 37. - INTERNAL USE ONLY - Files upload. Client import { createUploadLink } from 'apollo-upload-client' const link = createUploadLink(/* Options */) 37
  • 38. - INTERNAL USE ONLY - Files upload. Client export default graphql(gql` mutation($files: [Upload!]!) { uploadFiles(files: $files) { id } } `)(({ mutate }) => ( <input type="file" multiple onChange={({ target: { validity, files } }) => validity.valid && mutate({ variables: { files } }) } /> )) 38
  • 39. - INTERNAL USE ONLY - Pagination 39
  • 40. - INTERNAL USE ONLY - Pagination options: ({ queryVariables }) => ({ variables: queryVariables, notifyOnNetworkStatusChange: true, fetchPolicy: APOLLO_FETCH_POLICIES.CACHE_AND_NETWORK, }), 40
  • 41. - INTERNAL USE ONLY - Pagination props: ({ data: { error, loading: isLoading, items: { availableCount, results = [] } = {}, fetchMore, refetch, networkStatus, }, }) => {...} 41
  • 42. - INTERNAL USE ONLY - Pagination const isFirstPage = networkStatus !== APOLLO_NETWORK_STATUSES.FETCH_MORE; … return { ... /** * `() => refetch()` is *mandatory* in order to prevent event handlers from passing arguments such as *event* * to *Apollo* `refetch` function as it treats arguments as variables for GraphQL queries. * Otherwise, it would lead to errors in `JSON.parse(...)` when trying to parse circular data. */ refetch: () => refetch(), }; 42
  • 43. - INTERNAL USE ONLY - Pagination export const APOLLO_NETWORK_STATUSES = { FETCH_MORE: NetworkStatus.fetchMore, /** * networkStatus === ERROR *only* when http status is bad (e.g. 4xx, 5xx) * however usually you want to handle also errors in resolvers, e.g. * http status is 200 but response contains `errors` property. * Consider using Boolean(data.error) instead of (data.networkStatus === ERROR) */ ERROR: NetworkStatus.error, }; 43
  • 44. - INTERNAL USE ONLY - Pagination. More pitfalls • 1.x: fetchMore doesn’t trigger rerender on error 44
  • 45. - INTERNAL USE ONLY - Pagination. Imperative update query Feed($type: FeedType!, $offset: Int, $limit: Int) { currentUser { login } feed(type: $type, offset: $offset, limit: $limit) @connection(key: "feed") { id # ... } } … client.writeData 45
  • 46. - INTERNAL USE ONLY - Schema design 46
  • 47. - INTERNAL USE ONLY - Schema design “Design by client needs” 47
  • 48. - INTERNAL USE ONLY - Schema design • Use interfaces • Use QueryResponse • Use MutationResponse • Use input types • Use your clients style convention (GQL is flexible) 48
  • 49. - INTERNAL USE ONLY - Schema design. QueryResponse type DealResponse { availableCount: Int count: Int results: [Deal] } type Query { deals( text: String, ... ): DealResponse } 49
  • 50. - INTERNAL USE ONLY - Schema design. MutationResponse type LikePostMutationResponse implements MutationResponse { code: String! success: Boolean! message: String! post: Post user: User } 50
  • 51. - INTERNAL USE ONLY - Schema design. Input types input PostAndMediaInput { "A main title for the post" title: String "The textual body of the post." body: String "A list of URLs to render in the post." mediaUrls: [String] } 51
  • 52. - INTERNAL USE ONLY - ACL 52
  • 53. - INTERNAL USE ONLY - ACL Available options: • Delegate to REST API • Authorization via context • Authorization via directives 53
  • 54. - INTERNAL USE ONLY - ACL. Authorization via context context: ({ req }) => { const token = req.headers.authentication || ''; const user = getUser(token); if (!user) throw new AuthorizationError('you must be logged in'); return { user }; }, 54
  • 55. - INTERNAL USE ONLY - ACL. Authorization via context users: (root, args, context) => { // In this case, we'll pretend there is no data when // we're not logged in. Another option would be to // throw an error. if (!context.user) return []; return ['bob', 'jake']; } 55
  • 56. - INTERNAL USE ONLY - ACL. Authorization via directives directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION enum Role { ADMIN REVIEWER USER } type User @auth(requires: USER) { name: String banned: Boolean @auth(requires: ADMIN) canPost: Boolean @auth(requires: REVIEWER) } 56
  • 57. - INTERNAL USE ONLY - State management 57
  • 58. - INTERNAL USE ONLY - State management Since Apollo Client supports managing both local and remote data, you can use the Apollo cache as a single source of truth for all global state in your application. 58
  • 59. - INTERNAL USE ONLY - State management apollo-link-state const client = new ApolloClient({ uri: `https://nx9zvp49q7.lp.gql.zone/graphql`, clientState: { defaults, resolvers, typeDefs } }); 59
  • 60. - INTERNAL USE ONLY - State management. Defaults initialState → defaults 60
  • 61. - INTERNAL USE ONLY - State management. Resolvers export const resolvers = { Mutation: { toggleTodo: (_, variables, { cache, getCacheKey }) => { const id = getCacheKey({ __typename: 'TodoItem', id: variables.id }) const fragment = gql` fragment completeTodo on TodoItem { completed } `; const todo = cache.readFragment({ fragment, id }); const data = { ...todo, completed: !todo.completed }; cache.writeData({ id, data }); return null; 61
  • 62. - INTERNAL USE ONLY - State management. Query { todos @client { id completed text } visibilityFilter @client } 62
  • 63. - INTERNAL USE ONLY - State management 63
  • 64. - INTERNAL USE ONLY - Performance 64
  • 65. - INTERNAL USE ONLY - Performance Optimization points: • Do not send full query to server • Cache read requests • Cache entities on client • Prefetch entities • Batch requests 65
  • 66. - INTERNAL USE ONLY - Performance. Automatic Persisted Queries 66
  • 67. - INTERNAL USE ONLY - Performance. Automatic Persisted Queries curl -g 'http://localhost:9011/graphql?extensions={"persistedQuery":{"version":1,"sha256Hash":" ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"}}' 67
  • 68. - INTERNAL USE ONLY - Performance. Automatic Persisted Queries Client: apollo-link-persisted-queries Server: const server = new ApolloServer({ typeDefs, resolvers, persistedQueries: { cache: new InMemoryCache(), }, }); 68
  • 69. - INTERNAL USE ONLY - Performance. CDN integration createPersistedQueryLink({ useGETForHashedQueries: true }) ___ type Author @cacheControl(maxAge: 60) { id: Int firstName: String lastName: String posts: [Post] @cacheControl(maxAge: 180) } 69
  • 70. - INTERNAL USE ONLY - Performance. Client caching • Data is normalized and cached by default • Update mutation updates cached automagically • Create mutation requires manual cache writes 70
  • 71. - INTERNAL USE ONLY - Performance. Client caching <Mutation mutation={ADD_TODO} update={(cache, { data: { addTodo } }) => { const { todos } = cache.readQuery({ query: GET_TODOS }); cache.writeQuery({ query: GET_TODOS, data: { todos: todos.concat([addTodo]) } }); }} > Variables! (@connection) 71
  • 72. - INTERNAL USE ONLY - Performance. Client caching: cacheRedirects const cache = new InMemoryCache({ cacheRedirects: { Query: { book: (_, args, { getCacheKey }) => getCacheKey({ __typename: 'Book', id: args.id }) }, }, }); 72
  • 73. - INTERNAL USE ONLY - Performance. Prefetching <Component onMouseOver={() => client.query({ query: GET_DOG, variables: { breed: data.breed } }) } /> 73
  • 74. - INTERNAL USE ONLY - Performance. Batch requests import { BatchHttpLink } from "apollo-link-batch-http"; const link = new BatchHttpLink({ uri: "/graphql" }); 74
  • 75. - INTERNAL USE ONLY - Testing React components 75
  • 76. - INTERNAL USE ONLY - Testing React Components const mocks = [ { request: { query: GET_DOG_QUERY, variables: { name: 'Buck', }, }, result: { data: { dog: { id: '1', name: 'Buck', breed: 'bulldog' }, }, }, }, ]; 76
  • 77. - INTERNAL USE ONLY - Testing React Components it('renders without error', () => { renderer.create( <MockedProvider mocks={mocks} addTypename={false}> <Dog name="Buck" /> </MockedProvider>, ); }); 77
  • 78. - INTERNAL USE ONLY - Testing React Components: Loading state By default 78
  • 79. - INTERNAL USE ONLY - Testing React Components: Success state it('should render dog', async () => { // ... await wait(0); // wait for nextTick // ... }); 79
  • 80. - INTERNAL USE ONLY - Testing React Components: Error state const dogMock = { request: { query: GET_DOG_QUERY, variables: { name: 'Buck' }, }, error: new Error('aw shucks'), }; 80
  • 81. - INTERNAL USE ONLY - Server-side rendering 81
  • 82. - INTERNAL USE ONLY - Server-side rendering getDataFromTree(App).then(() => { const content = ReactDOM.renderToString(App); const initialState = client.extract(); const html = <Html content={content} state={initialState} />; res.status(200); res.send(`<!doctype html>n${ReactDOM.renderToStaticMarkup(html)}`); res.end(); }); 82
  • 83. - INTERNAL USE ONLY - Server-side rendering function Html({ content, state }) { return ( <html> <body> <div id="root" dangerouslySetInnerHTML={{ __html: content }} /> <script dangerouslySetInnerHTML={{ __html: `window.__APOLLO_STATE__=${JSON.stringify(state).replace(/</g, 'u003c')};`, }} /> </body> </html> ); } 83
  • 84. - INTERNAL USE ONLY - Server-side rendering. Avoid network calls const client = new ApolloClient({ ssrMode: true, link: new SchemaLink({ schema }), cache: new InMemoryCache(), }); 84
  • 85. - INTERNAL USE ONLY - Server-side rendering. Skipping queries const ClientOnlyUser = () => ( <Query query={GET_USER_WITH_ID} ssr={false}> {({ data }) => <span>I won't be run on the server</span>} </Query> ); 85
  • 86. - INTERNAL USE ONLY - Server-side rendering. Rehydration const client = new ApolloClient({ cache: new InMemoryCache().restore(window.__APOLLO_STATE__), link, }); 86
  • 87. - INTERNAL USE ONLY - Apollo 2.1 87
  • 88. - INTERNAL USE ONLY - Apollo 2.1 <Query> / <Mutation> / <Subscription> <ApolloConsumer /> Apollo Devtools 88
  • 89. - INTERNAL USE ONLY - Relay 89
  • 90. - INTERNAL USE ONLY - Relay https://open.nytimes.com/the-new-york-times-now-on-apollo- b9a78a5038c “Relay takes a “bring your own solution” approach to this problem. In Apollo, SSR is a first-class feature. This is huge for us.” 90
  • 91. - INTERNAL USE ONLY - Conclusion 91
  • 92. - INTERNAL USE ONLY - Conclusion Apollo is a fully-featured open-source* platform 92
  • 93. - INTERNAL USE ONLY - Questions? 93