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

From REST to GraphQL

From REST to GraphQL

Marc-Andre Giroux

September 06, 2016
Tweet

More Decks by Marc-Andre Giroux

Other Decks in Programming

Transcript

  1. From REST to GraphQL
    Marc-Andre Giroux @__xuorig__

    View Slide

  2. About me

    View Slide

  3. View Slide

  4. A simple UI component

    View Slide

  5. View Slide

  6. What kind of data is needed?

    View Slide

  7. Cart Product ProductImage

    View Slide

  8. Reusable endpoints (REST)

    View Slide

  9. /carts/1
    /products/1
    /products/2
    /products/3
    /product_images/1
    /product_images/2
    /product_images/3

    View Slide

  10. Too many round trips!

    View Slide

  11. /carts/1?expand=products

    View Slide

  12. /carts/1?fields=products(name, description, price)

    View Slide

  13. /carts/1?fields=products/name,description,price

    View Slide

  14. Custom Endpoints

    View Slide

  15. /cart_with_all_the_stuff_i_need

    View Slide

  16. View Slide

  17. /cart_with_all_the_stuff_i_need
    /cart_version_2_with_all_the_things
    /cart_with_products_and_images
    /cart_with_products_and_images_with_price_and_taxes
    my_tightly_coupled_custom_endpoint_including_only_the_things_i_need_bla_bla_bla_bla
    /cart_with_products_and_images_with_price_and_taxes_but_no_description
    /cart_with_products_and_images_with_price_and_taxes_but_no_description_v2

    View Slide

  18. View Slide

  19. Server Client
    Updates a view
    Creates a new view
    Product view v2
    Product model changes
    Update endpoints
    Create new endpoint

    View Slide

  20. GraphQL

    View Slide

  21. What GraphQL is NOT

    View Slide

  22. What GraphQL IS

    View Slide

  23. {
    myShop {
    name
    }
    } Field
    Selection Set

    View Slide

  24. {
    myShop {
    name
    }
    }
    Lexed
    Parsed
    Validated
    Executed
    {
    “myShop” {
    “name”: “GitHub”
    }
    }

    View Slide

  25. {
    myShop {
    name
    }
    }

    View Slide

  26. {
    myShop {
    name
    }
    }

    View Slide

  27. View Slide

  28. {
    shop(id: 1) {
    name
    }
    }

    View Slide

  29. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  30. {
    “myShop”: {
    “name”: “Full Stack Fest Shop”
    “location” {
    “city”: “Barcelona”
    “address”: “Av. Diagonal 547”
    }
    “products”: [{
    “name”: “Conference Ticket”
    “price”: 500000
    }, {
    “name”: “Cool T-Shirt”
    “price”: 20000
    }]
    }
    }

    View Slide

  31. Type System

    View Slide

  32. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  33. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  34. type QueryRoot {
    myShop: Shop
    shop(id: Int): Shop
    }

    View Slide

  35. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  36. type Shop {
    name: String
    location: Address
    products(orderby: OrderEnum): [Product]
    }
    enum ProductOrderEnum {
    PRICE,
    POPULARITY,
    ALPHABETICAL
    }

    View Slide

  37. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  38. type Address {
    city: String
    address: String
    }

    View Slide

  39. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    name
    price
    }
    }
    }

    View Slide

  40. type Product {
    name: String
    price: Int
    }

    View Slide

  41. Fragments

    View Slide

  42. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    id
    name
    price
    }
    }
    }

    View Slide

  43. View Slide

  44. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    id
    name
    price
    }
    }
    }

    View Slide

  45. fragment productFields on Product {
    id
    name
    price
    }

    View Slide

  46. {
    myShop {
    name
    location {
    city
    address
    }
    products(orderby: POPULARITY) {
    ...productFields
    }
    }
    }

    View Slide

  47. query
    Fragment
    Fragment
    Fragment Fragment

    View Slide

  48. Introspection

    View Slide

  49. query {
    __schema {

    }
    }

    View Slide

  50. Static Validation
    Code Generation
    IDE Integration
    Auto Documentation

    View Slide

  51. View Slide

  52. View Slide

  53. Resolving fields

    View Slide

  54. type Product {
    name: String
    price: Int
    }

    View Slide

  55. ProductType = GraphQL::ObjectType.define do
    name "Product"
    description “A product sold at a shop”
    # …
    end

    View Slide

  56. field :name do
    type types.String
    resolve -> (obj, args, ctx) { obj.name }
    end

    View Slide

  57. field :price do
    type types.Int
    resolve -> (obj, args, ctx) do
    obj.subtotal + obj.taxes + obj.shipping_price
    end
    end

    View Slide

  58. field :price do
    type types.Int
    resolve -> (obj, args, ctx) do
    obj.subtotal + obj.taxes + obj.shipping_price
    end
    end

    View Slide

  59. POST /graphql

    View Slide

  60. Mutations

    View Slide

  61. mutation {
    createProduct(name: “Nice Mug”, price: 10000) {
    id
    name
    }
    }

    View Slide

  62. Drawbacks
    and solutions

    View Slide

  63. N+1 Queries

    View Slide

  64. field :image do
    type ImageType
    resolve -> (product, args, ctx) do
    product.image
    end
    end
    field :products do
    type [ProductType]
    resolve -> (shop, args, ctx) do
    shop.products
    end
    end

    View Slide

  65. Product Load (1.0ms) SELECT "products".* FROM "products"
    WHERE "products"."shop_id" = …
    Image Load (0.9ms) SELECT "images".* FROM "images"
    WHERE "images"."product_id" = …
    Image Load (0.2ms) SELECT "images".* FROM "images"
    WHERE "images"."product_id" = …
    Image Load (0.1ms) SELECT "images".* FROM "images"
    WHERE "images"."product_id" = …

    View Slide

  66. Solution: Batching + Caching

    View Slide

  67. field :image do
    type ImageType
    resolve -> (product, args, ctx) do
    RecordLoader.for(Image).load(product.image_id)
    end
    end

    View Slide

  68. HTTP Caching

    View Slide

  69. Solution: Client Side Cache

    View Slide

  70. Normalized Cache

    View Slide

  71. Normalized Cache

    View Slide

  72. query {
    shop {
    products {
    price
    }
    }
    }
    query {
    shop {
    product(id: 1) {
    price
    }
    }
    }

    View Slide

  73. {
    root: {
    shop: {
    products: [
    Link.new(1)
    ]
    }
    },
    1: {
    price: 1000
    }
    }

    View Slide

  74. https://github.com/facebook/relay http://www.apollostack.com/

    View Slide

  75. Security

    View Slide

  76. Query Depth
    Timeouts
    Query Complexity

    View Slide

  77. Future

    View Slide

  78. Subscriptions

    View Slide

  79. subscription {
    productInventorySubscribe {
    products {
    inventory
    }
    }
    }

    View Slide

  80. Deferred Queries

    View Slide

  81. query {
    shop {
    name
    description
    products {
    name
    price
    }
    }
    }

    View Slide

  82. query {
    shop {
    name
    description
    products {
    name
    price
    }
    }
    }

    View Slide

  83. query {
    shop {
    name
    description
    products @defer {
    name
    price
    }
    }
    }

    View Slide

  84. View Slide

  85. View Slide

  86. Thank you
    Marc-Andre Giroux @__xuorig__

    View Slide