Slide 1

Slide 1 text

GRAPHQL ON MICROSERVICES LANDSCAPE Sergey Ponomarev How to put it all together

Slide 2

Slide 2 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup 2 @sponomarev @bufo_alvarius Sergey Ponomarev

Slide 3

Slide 3 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup 3

Slide 4

Slide 4 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup 4

Slide 5

Slide 5 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup 5 evilmartians.com

Slide 6

Slide 6 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup evilmartians.com/chronicles 6

Slide 7

Slide 7 text

(MICRO)SERVICES

Slide 8

Slide 8 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup WHY? ‣ Decomposition ‣ Best tools for a task ‣ Scalability ‣ etc. 8

Slide 9

Slide 9 text

DISTRIBUTED DATA

Slide 10

Slide 10 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MY AWESOME MONOLITH 10

Slide 11

Slide 11 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MY AWESOME SERVICES 11

Slide 12

Slide 12 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup INTERNAL COMMUNICATIONS 12

Slide 13

Slide 13 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MESSAGE BUS 13

Slide 14

Slide 14 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MESSAGE BUS 14

Slide 15

Slide 15 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup EXTERNAL COMMUNICATIONS 15

Slide 16

Slide 16 text

THERE ARE MANY OF THEM, AND I AM ALONE

Slide 17

Slide 17 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup NAME THEM ALL ‣ store.api.awesome.store ‣ payments.api.awesome.store ‣ auth.api.awesome.store ‣ chat.api.awesome.store ‣ etc… 17

Slide 18

Slide 18 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ‣ Separate requests ‣ Different protocols ‣ Hard to manage and refactor 18

Slide 19

Slide 19 text

ONE ON ONE

Slide 20

Slide 20 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup API GATEWAY 20

Slide 21

Slide 21 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup COMBINE AND CONQUER ‣ api.awesome.store • /products • /orders • /profile • /messages • etc… 21

Slide 22

Slide 22 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ‣ Simplified interface ‣ Complexity is hidden ‣ Single protocol ‣ Additional features* 22

Slide 23

Slide 23 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup 23

Slide 24

Slide 24 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ‣ One request ‣ No over- and under-fetching problems ‣ Docs out-of-the-box ‣ Frontenders ❤ us 24

Slide 25

Slide 25 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup query { orders { createdAt product { name price } payment { createdAt } } } 25

Slide 26

Slide 26 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup query { orders { # orders service createdAt product { # store service name price } payment { # payments service createdAt } } } 26

Slide 27

Slide 27 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup query { orders { # orders service id productId createdAt product { # store service name price } payment { # payments service createdAt } } } 27

Slide 28

Slide 28 text

SCHEMA STITCHING

Slide 29

Slide 29 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ORDERS 29 type Query { orders: [Order] } type Order { id: Int! productId: Int! createdAt: Date! }

Slide 30

Slide 30 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup PRODUCTS 30 type Query { product(id: Int!): Product } type Product { id: Int! name: String! price: Float! }

Slide 31

Slide 31 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup PAYMENTS 31 type Query { payment(orderId: Int!): Payment } type Payment { id: Int! orderId: Int! createdAt: Date! }

Slide 32

Slide 32 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup REMOTE SCHEMA 32 const link = new HttpLink({ uri: 'http: //store.api', fetch }); const schema = await introspectSchema(link); const ordersSchema = makeRemoteExecutableSchema({ schema, link, });

Slide 33

Slide 33 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup EXTENDED SCHEMA 33 extend type Order { product: Product! payment: Payment! }

Slide 34

Slide 34 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MERGE SCHEMAS 34 mergeSchemas({ schemas: [ ordersSchema, productsSchema, paymentsSchema, extendedSchema, ], });

Slide 35

Slide 35 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup RESOLVERS 35 Order: { product: { fragment: ' ... on Order { productId }', resolve(order, args, context, info) { return info.mergeInfo.delegateToSchema({ schema: productSchema, operation: 'query', fieldName: 'product', args: { id: order.productId, }, context, info, }); }, }, },

Slide 36

Slide 36 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup SCHEMA STITCHING ✅ Compose distributed graph ✅ Grained control over the final schema ❌ Requires additional code ❌ Imperative management ❌ Allows bad practices 36

Slide 37

Slide 37 text

GRAPHQL FEDERATION

Slide 38

Slide 38 text

GRAPHQL FEDERATION

Slide 39

Slide 39 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup APOLLO FEDERATION ✅ Compose distributed graph ✅ Does not require additional code ✅ Declarative management ✅ Stimulates conventions, standards 39

Slide 40

Slide 40 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup TOOLS @apollo/federation @apollo/gateway 40

Slide 41

Slide 41 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup GATEWAY 41 const gateway = new ApolloGateway({ serviceList: [ { name: 'orders', url: 'http: //store.api' }, { name: 'products', url: 'http: //products.api' }, { name: 'payments', url: 'http: //payments.api' }, ], }); const server = new ApolloServer({ gateway }); server.listen();

Slide 42

Slide 42 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ORDERS 42 extend type Query { orders: [Order] } type Order @key(fields: "id") { id: Int! productId: Int! createdAt: Date! }

Slide 43

Slide 43 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup PRODUCTS 43 type Product @key(fields: "id") { id: Int! name: String! price: Float! } extend type Order @key(fields: "id") { id: Int! @external productId: Int! @external product: Product! @requires(fields: "productId") }

Slide 44

Slide 44 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup PAYMENTS 44 type Payment { id: Int! orderId: Int! createdAt: Date! } extend type Order @key(fields: "id") { id: Int! @external payment: Payment! }

Slide 45

Slide 45 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup RESOLVERS: ENTITIES 45 const resolvers = { Order: { __resolveReference(order, { fetchOrderById }) { return fetchOrderById(order.id); }, }, };

Slide 46

Slide 46 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup RESOLVERS: EXTENSIONS 46 const resolvers = { Order: { product(order, { fetchProductById }) { return fetchProductById(order.productId); }, }, };

Slide 47

Slide 47 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY query { orders { createdAt product { name price } payment { createdAt } } } 47

Slide 48

Slide 48 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY PLAN 48 QueryPlan { Sequence { Fetch(service: "orders") { { orders { createdAt __typename id productId } } }, ...

Slide 49

Slide 49 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY PLAN 49 Parallel { Flatten(path: "orders.@") { Fetch(service: "products") { ... }, }, Flatten(path: "orders.@") { Fetch(service: "payments") { ... }, }, },

Slide 50

Slide 50 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY PLAN 50 Fetch(service: "products") { { ... on Order { __typename id productId } } => { ... on Order { product { name price } } } },

Slide 51

Slide 51 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY PLAN 51 Fetch(service: "payments") { { ... on Order { __typename id } } => { ... on Order { payment { createdAt } } } },

Slide 52

Slide 52 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup FEDERATION SPECS 52

Slide 53

Slide 53 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup SCHEMA 53 scalar _Any scalar _FieldSet # a union of all types that use the @key directive union _Entity type _Service { sdl: String } extend type Query { _entities(representations: [_Any!]!): [_Entity]! _service: _Service! } directive @external on FIELD_DEFINITION directive @requires(fields: _FieldSet!) on FIELD_DEFINITION directive @provides(fields: _FieldSet!) on FIELD_DEFINITION directive @key(fields: _FieldSet!) on OBJECT | INTERFACE directive @extends on OBJECT | INTERFACE

Slide 54

Slide 54 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup SERVICE 54 ‣ _service ‣ _entities ‣ Schema “normalization” • Stub types • Resolvers for stub types

Slide 55

Slide 55 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup TOOLING 55

Slide 56

Slide 56 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup NO GATEWAY ALTERNATIVES 56

Slide 57

Slide 57 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MANAGED SCHEMA 57 ‣ Validate schema changes against real queries ‣ Validate schema composition before the gateway ‣ “Live” schema update

Slide 58

Slide 58 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup APOLLO FEDERATION ✅ Compose distributed graph ❓ Grained control over the final schema ✅ Does not require boilerplate code ✅ Declarative management ✅ Stimulates conventions, standards 58

Slide 59

Slide 59 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup WARNING ⚠ New technology, low adoption level ⚠ No support for subscriptions yet ⚠ Vendor lock (no self-hosted solutions for managed schema yet) 59

Slide 60

Slide 60 text

THANKS! Sergey Ponomarev evilmartians.com/chronicles @sponomarev @bufo_alvarius @evilmartians

Slide 61

Slide 61 text

@bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup CREDITS 61 Moscow-City | Deensel | Flickr DUMBO | An overly shot subject, but I couldn’t help myself. | Flickr Broken Bottle Flat Lay 7655 B | Broken bottles and flasks | Flickr Sport Action | Fencing | Qrodo Photos | Flickr Stitch | 35/366 | Kevin Doncaster | Flickr Free Images : hand, wood, alone, food, pebble, speech, lecture, outsider, discussion, symbolic, one against all, all against one, game characters, dispute, bullying, follower, flooring 5724x3110 - - 418403 - Free stock photos - PxHere cube | Richard Cassan | Flickr