SlideShare a Scribd company logo
1 of 93
Download to read offline
- 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 Zendcon09Michelangelo 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.1Patrycja Wegrzynowicz
 
PofEAA and SQLAlchemy
PofEAA and SQLAlchemyPofEAA and SQLAlchemy
PofEAA and SQLAlchemyInada Naoki
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805t k
 
Flask patterns
Flask patternsFlask patterns
Flask patternsit-people
 
Flask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuthFlask RESTful Flask HTTPAuth
Flask RESTful Flask HTTPAuthEueung Mulyana
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate 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) BridgeJosé Paumard
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtupt 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.8Michelangelo van Dam
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance IssuesOdoo
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6Technopark
 
Filling the flask
Filling the flaskFilling the flask
Filling the flaskJason 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 ToolsSeth Miller
 
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'sRoel 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 frameworkBen 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 Gearsdion
 
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).pdfRahulRoy130127
 
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 - mumbaiPraveen Puglia
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript EverywherePascal Rettig
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomyDongmin Yu
 
服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScript服务框架: Thrift & PasteScript
服务框架: Thrift & PasteScriptQiangning 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 NYPuppet
 
Diseño y Desarrollo de APIs
Diseño y Desarrollo de APIsDiseño y Desarrollo de APIs
Diseño y Desarrollo de APIsRaúl Neis
 
Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCLFastly
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsIvá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 TeamNETWAYS
 
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 2010Arun Gupta
 
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 platformsAyush 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

Study on Air-Water & Water-Water Heat Exchange in a Finned Tube Exchanger
Study on Air-Water & Water-Water Heat Exchange in a Finned Tube ExchangerStudy on Air-Water & Water-Water Heat Exchange in a Finned Tube Exchanger
Study on Air-Water & Water-Water Heat Exchange in a Finned Tube ExchangerAnamika Sarkar
 
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionDr.Costas Sachpazis
 
Heart Disease Prediction using machine learning.pptx
Heart Disease Prediction using machine learning.pptxHeart Disease Prediction using machine learning.pptx
Heart Disease Prediction using machine learning.pptxPoojaBan
 
Call Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call GirlsCall Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call Girlsssuser7cb4ff
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.eptoze12
 
pipeline in computer architecture design
pipeline in computer architecture  designpipeline in computer architecture  design
pipeline in computer architecture designssuser87fa0c1
 
Effects of rheological properties on mixing
Effects of rheological properties on mixingEffects of rheological properties on mixing
Effects of rheological properties on mixingviprabot1
 
Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvLewisJB
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfAsst.prof M.Gokilavani
 
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...srsj9000
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)Dr SOUNDIRARAJ N
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...Chandu841456
 
GDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSCAESB
 
What are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptxWhat are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptxwendy cai
 
DATA ANALYTICS PPT definition usage example
DATA ANALYTICS PPT definition usage exampleDATA ANALYTICS PPT definition usage example
DATA ANALYTICS PPT definition usage examplePragyanshuParadkar1
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidNikhilNagaraju
 
Call Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile serviceCall Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile servicerehmti665
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVRajaP95
 
Internship report on mechanical engineering
Internship report on mechanical engineeringInternship report on mechanical engineering
Internship report on mechanical engineeringmalavadedarshan25
 

Recently uploaded (20)

Study on Air-Water & Water-Water Heat Exchange in a Finned Tube Exchanger
Study on Air-Water & Water-Water Heat Exchange in a Finned Tube ExchangerStudy on Air-Water & Water-Water Heat Exchange in a Finned Tube Exchanger
Study on Air-Water & Water-Water Heat Exchange in a Finned Tube Exchanger
 
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
 
Heart Disease Prediction using machine learning.pptx
Heart Disease Prediction using machine learning.pptxHeart Disease Prediction using machine learning.pptx
Heart Disease Prediction using machine learning.pptx
 
Call Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call GirlsCall Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call Girls
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.
 
pipeline in computer architecture design
pipeline in computer architecture  designpipeline in computer architecture  design
pipeline in computer architecture design
 
Effects of rheological properties on mixing
Effects of rheological properties on mixingEffects of rheological properties on mixing
Effects of rheological properties on mixing
 
Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvv
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
 
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...
 
GDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentation
 
What are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptxWhat are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptx
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
DATA ANALYTICS PPT definition usage example
DATA ANALYTICS PPT definition usage exampleDATA ANALYTICS PPT definition usage example
DATA ANALYTICS PPT definition usage example
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfid
 
Call Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile serviceCall Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile service
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
 
Internship report on mechanical engineering
Internship report on mechanical engineeringInternship report on mechanical engineering
Internship report on mechanical engineering
 

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