Slide 1

Slide 1 text

BUILDING COMPELLING REALTIME WEB EXPERIENCES @ROBDCROWLEY | ROBDCROWLEY

Slide 2

Slide 2 text

▪ GRAPHQL OVERVIEW ▪ THE CASE FOR REALTIME EXPERIENCES ▪ THE SERVER STORY ▪ A CLIENT PERSPECTIVE ▪ MAKING IT ALL PERFORMANT

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Slide 5

Slide 5 text

♥ AND I’M FINE WITH THAT!

Slide 6

Slide 6 text

MANY TYPES OF CLIENTS CAN CONSUME OUR APIS

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

HOW CAN EACH CLIENT RETRIEVE EXACTLY THE DATA IT REQUIRES IN A SINGLE ROUND TRIP TO THE SERVER?

Slide 9

Slide 9 text

SHOW ME HOW GRAPHQL WORKS ALREADY!

Slide 10

Slide 10 text

type Actor implements Node { id: ID! name: String appearedIn: [Film] netWorth: MonetaryAmount }

Slide 11

Slide 11 text

let queryFilm = (_, {id}, {models}) => { // arbitrary code to retrieve film return models.film.get(id); } let filmTitle = film => { // just return property from root film return film.title; }

Slide 12

Slide 12 text

THE ABSOLUTE MINIMUM YOU NEED TO KNOW (PROBABLY)

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

query { film(id: “2”) { title characters { name actors { name } } } }

Slide 16

Slide 16 text

query { film(id: “2”) { title characters { name actors { name } } } }

Slide 17

Slide 17 text

query { film(id: “2”) { title characters { name actors { name } } } }

Slide 18

Slide 18 text

query { film(id: “2”) { title characters { name actors { name } } } }

Slide 19

Slide 19 text

query { film(id: “2”) { title characters { name actors { name } } } }

Slide 20

Slide 20 text

▪ IS A QUERY LANGUAGE FOR YOUR API ▪ ALLOWS CLIENTS TO CRAFT STRONGLY TYPED QUERIES ▪ FACILITATES RETRIEVING EXACTLY THE DATA YOU REQUIRE ▪ HAS POWERFUL FEATURES SUCH AS INTROSPECTION ▪ IS PRETTY COOL ☺

Slide 21

Slide 21 text

WHY IS IT IMPORTANT?

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

CUSTOMERS EXPECT THEIR DATA TO BE AVAILABLE IN REALTIME. THIS HAS ALREADY HAPPENED AND WE NEED TO CATCH UP .

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

GREAT WHEN THE DATA REFRESH RATE IS KNOWN OTHERWISE WE NEED TO BALANCE FRESHNESS AND CHATTINESS

Slide 27

Slide 27 text

DATA REFRESH IS BASED ON OBSERVING STATE ON THE SERVER THINK INFINITELY FAST POLLING

Slide 28

Slide 28 text

query @live { film(filmId: 2) { title description reviews { aggregateRating { average } } } }

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

DATA REFRESH IS BASED ON OBSERVING EVENTS READ-ONLY / NOT A REPLACEMENT FOR QUERIES

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

subscription onReviewAdded { reviewAdded { review { rating } film { title } } }

Slide 35

Slide 35 text

mutation addReview { addReview(input: { clientMutationId: “MjpGaWxt” content: “Quirky and darkly funny”, rating: 9, filmId: 5 }) { clientMutationId } }

Slide 36

Slide 36 text

{ reviewAdded: { review: { rating:9 } film: { title: “Fargo” } } }

Slide 37

Slide 37 text

USING GRAPHQL PLAYGROUND

Slide 38

Slide 38 text

GRAPHQL PROVIDES A CONSISTENT INTERFACE FOR BOTH PUSH AND PULL INTERACTIONS

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

▪ IS SUPPORTED VIA POLLING / SUBSCRIPTIONS / LIVE QUERIES. ▪ AFFORDS A CONSISTENT INTERFACE FOR SYNC AND ASYNC QUERIES VIA SUBSCRIPTIONS. ▪ IS VERY POWERFUL WHEN USED APPROPRIATELY.

Slide 41

Slide 41 text

GRAPHQL FROM A CONSUMER PERSPECTIVE

Slide 42

Slide 42 text

DX IS KEY TO DELIVERING A SUCCESS API

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

MINIMAL GRAPHQL CLIENT SUPPORTING NODE AND BROWSERS FOR SCRIPTS OR SIMPLE APPS

Slide 45

Slide 45 text

import { request } from ‘graphql-request’ const query = `{ film(filmId: “2”) { title description releasedOn } }` request(‘https://api.example.com/graphql’, query) .then(data => console.log(data))

Slide 46

Slide 46 text

FACEBOOK’S FRAMEWORK FOR BUILDING DATA DRIVEN APPLICATIONS USING GRAPHQL

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

type Actor implements Node { id: ID! actorId: ID! name: String appearedIn: ActorFilmsConnection }

Slide 49

Slide 49 text

type Genre implements Node { id: ID! name: String! description: String } type FilmGenresConnection { edges: [FilmGenresEdge] nodes: [Genre] pageInfo: PageInfo! totalCount: Int! } type FilmGenresEdge { cursor: String! node: Genre }

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

ULTRA-FLEXIBLE, FULL FEATURED, COMMUNITY-DRIVEN CLIENT

Slide 52

Slide 52 text

USING APOLLO CLIENT + REACT

Slide 53

Slide 53 text

POR QUÉ NO LOS DOS

Slide 54

Slide 54 text

HOW FAST IS FAST ENOUGH?

Slide 55

Slide 55 text

A SLOW RESOLVER WILL DELAY THE ENTIRE RESPONSE

Slide 56

Slide 56 text

DEFERRED QUERIES ENABLE OPTIMIZED DATA LOADING BY PREVENTING SLOW FIELDS FROM DELAYING THE ENTIRE RESPONSE

Slide 57

Slide 57 text

type Review implements Node @defer { id: ID! rating: Rating! content: String! @defer film: Film! createdAt: DateTime! }

Slide 58

Slide 58 text

query { film(id: “5”) { title reviewsConnection { edges { node { rating content } } } } }

Slide 59

Slide 59 text

{ “data”: { “film”: { “title”: “Fargo”, “reviewsConnection”: { “edges”: [ { “node”: null } ] } } } } }

Slide 60

Slide 60 text

{ “path”: [ “film”, “reviewsConnection”, “edges”, 1, “node” ], “data”: { “rating”: 9, “content”: null } }

Slide 61

Slide 61 text

{ “path”: [ “film”, “reviewsConnection”, “edges”, 1, “node”, “content” ], “data”: { “content”: “Witty and funny” } }

Slide 62

Slide 62 text

LOADING STATE TO THE RESCUE

Slide 63

Slide 63 text

{({ loading, error, data, loadingState }) => { if (loading) return
Loading...
; if (error) return
Error :(
; return (
{loadingState.review.content ? data.review.content : “Review content pending...”}
); }}

Slide 64

Slide 64 text

PESISTED QUERIES REDUCE NETWORK TRAFFIC VOLUMES AND PROVIDE PROTECTION AGAINST PATHALOGICAL QUERIES

Slide 65

Slide 65 text

new ApolloServer({ typeDefs, resolvers, engine: { apiKey: config.apolloEngineKey }, persistedQueries: { cache: new RedisCache({ host: config.queryCache.host, port: config.queryCache.port }) }, });

Slide 66

Slide 66 text

hash:‘4fa973c’ hash:‘4fa973c’ query { film(id: “5”) { title } } { data: { film { title } } }

Slide 67

Slide 67 text

hash:‘4fa973c’ { data: { film { title } } } query { film(id: “5”) { title } }

Slide 68

Slide 68 text

HASHED QUERIES CAN BE SENT AS HTTP GET REQUESTS WITH APOLLO CLIENT TO ENABLE CACHING.

Slide 69

Slide 69 text

yarn add apollo-link-persisted-queries

Slide 70

Slide 70 text

new ApolloClient({ connectToDevTools: true, link: ApolloLink.from([ createPersistedQueryLink({ useGETForHashedQueries: true }), createHttpLink({ uri: “/graphql” }), ]), cache: new InMemoryCache() });

Slide 71

Slide 71 text

type Review implements Node { id: ID! rating: Rating! content: String! film: Film! @cacheControl(maxAge: 60) createdAt: DateTime! }

Slide 72

Slide 72 text

LOVE YOUR USERS BUT DON’T BLINDLY TRUST THEM

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

function resolver( root, args, context, info) { // l33t codez }

Slide 75

Slide 75 text

LIMIT THE COMPLEXITY OF QUERIES SOLELY BY THEIR DEPTH.

Slide 76

Slide 76 text

yarn add graphql-depth-limit

Slide 77

Slide 77 text

query { film { title reviews { aggregateRating { average } } } }

Slide 78

Slide 78 text

SET DATA CONSUMPTION LIMITS TO PROTECT AGAINST DOS ATTACKS

Slide 79

Slide 79 text

yarn add graphql-cost-analysis

Slide 80

Slide 80 text

type Review implements Node { id: ID! rating: Rating! content: String! @cost(complexity: 2) film: Film! @cacheControl(maxAge: 60) createdAt: DateTime! }

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪