Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphQL on Microservices Landscape

GraphQL on Microservices Landscape

It seems that GraphQL forces us to use a monolithic architecture. Single graph equals a single backend service, doesn't it? Let's see that it is not true and what we can do with that.

Sergey Ponomarev

December 19, 2019
Tweet

More Decks by Sergey Ponomarev

Other Decks in Programming

Transcript

  1. @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
  2. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ‣ Separate requests ‣

    Different protocols ‣ Hard to manage and refactor 18
  3. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup COMBINE AND CONQUER ‣

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

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

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

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

    # orders service createdAt product { # store service name price } payment { # payments service createdAt } } } 26
  8. @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
  9. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup ORDERS 29 type Query

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

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

    { payment(orderId: Int!): Payment } type Payment { id: Int! orderId: Int! createdAt: Date! }
  12. @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, });
  13. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup MERGE SCHEMAS 34 mergeSchemas({

    schemas: [ ordersSchema, productsSchema, paymentsSchema, extendedSchema, ], });
  14. @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, }); }, }, },
  15. @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
  16. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup APOLLO FEDERATION ✅ Compose

    distributed graph ✅ Does not require additional code ✅ Declarative management ✅ Stimulates conventions, standards 39
  17. @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();
  18. @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! }
  19. @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") }
  20. @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! }
  21. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup RESOLVERS: ENTITIES 45 const

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

    resolvers = { Order: { product(order, { fetchProductById }) { return fetchProductById(order.productId); }, }, };
  23. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY query { orders

    { createdAt product { name price } payment { createdAt } } } 47
  24. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup QUERY PLAN 48 QueryPlan

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

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

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

    "payments") { { ... on Order { __typename id } } => { ... on Order { payment { createdAt } } } },
  28. @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
  29. @bufo_alvarius @sponomarev Tver.IO, 9th Anniversary Meetup SERVICE 54 ‣ _service

    ‣ _entities ‣ Schema “normalization” • Stub types • Resolvers for stub types
  30. @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
  31. @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
  32. @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
  33. @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