O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky | Ruby Meditation 29

248 visualizações

Publicada em

Talk of Roman Dubrovsky, Backend developer at Datarockets, at Ruby Meditation #29 Kyiv 14.12.2019
Next conference - http://www.rubymeditation.com/

Description:
More than two years we’re developing and supporting GraphQL API, tried to make it public and integrated our app with other GraphQL APIs. In this talk, I'll try to summarize our experience, say about good practices, issues we found and can resolve. And which we can’t.
I will show you how to set up and how to use them.


Announcements and conference materials https://www.fb.me/RubyMeditation
News https://twitter.com/RubyMeditation
Photos https://www.instagram.com/RubyMeditation
The stream of Ruby conferences (not just ours) https://t.me/RubyMeditation

Publicada em: Tecnologia
  • Login to see the comments

  • Seja a primeira pessoa a gostar disto

Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky | Ruby Meditation 29

  1. 1. with ❤from datarockets Roman Dubrovsky 2 https://t.me/rdubrovsky https://github.com/roman-dubrovsky https://www.instagram.com/romandubrovsky
  2. 2. with ❤from datarockets 4
  3. 3. with ❤from datarockets 5 13:45 pm
  4. 4. with ❤from datarockets 6 13:45 pm 13:30 pm
  5. 5. with ❤from datarockets 7
  6. 6. with ❤from datarockets Minsk 8
  7. 7. with ❤from datarockets Minsk 9 Kiev
  8. 8. with ❤from datarockets Minsk 10 Kiev
  9. 9. datarockets https://datarockets.com https://github.com/datarockets/career https://www.instagram.com/datarockets https://twitter.com/datarockets https://www.facebook.com/datarockets
  10. 10. with ❤from datarockets Minsk.rb 13
  11. 11. LIFE WITH GRAPHQL API GOOD PRACTICES AND UNRESOLVED ISSUES with ❤ from datarockets
  12. 12. with ❤from datarockets In this talk ● Our adventure with GraphQL API: from small component on some pages to the SPA which includes the big part of application functionality ● Real issues we faced during creating and supporting our GraphQL API ● Issues I discussed with people on afterparties 🍻 ● Unresolved issues and my ideas and vision on designing the GraphQL API ● Why I love GraphQL ❤ 15
  13. 13. with ❤from datarockets Our GraphQL experience ● Almost 3 years of GraphQL API development for our SPA ● Made GraphQL API public for our customers ● Integrated with a number of external GraphQL APIs ● Drunk about 100 bottles of beer discussing GraphQL on afterparties 16
  14. 14. with ❤from datarockets Our GraphQL experience ● Almost 3 years of GraphQL API development for our SPA ● Made GraphQL API public for our customers ● Integrated with a number of external GraphQL APIs ● Drunk about 100 bottles of beer discussing GraphQL on afterparties 17 🍻
  15. 15. Part 0
  16. 16. GraphQL
  17. 17. with ❤from datarockets 20
  18. 18. Для тех кто в танке? Шутка про минск?
  19. 19. Для тех кто в танке? Шутка про минск?
  20. 20. with ❤from datarockets Type 24
  21. 21. with ❤from datarockets Fields 25
  22. 22. with ❤from datarockets Field to another type 26
  23. 23. with ❤from datarockets Thinking in Graphs 27
  24. 24. with ❤from datarockets Where is logic? 28
  25. 25. with ❤from datarockets Where do we store our logic? 29
  26. 26. with ❤from datarockets Where do we store our logic? Fields 30
  27. 27. with ❤from datarockets Where do we store our logic? Fields Resolvers 31
  28. 28. with ❤from datarockets Query type 32 User Organization me organization(id) QueryType
  29. 29. with ❤from datarockets Query type 33 QueryType me request query { me { // .... } } organization(id) User Organization
  30. 30. with ❤from datarockets Mutation type 34 MutationType CreatePost PublishPost createPost(postData) publishPost(postId)
  31. 31. with ❤from datarockets 35
  32. 32. with ❤from datarockets Typical depression 36 Type
  33. 33. with ❤from datarockets Typical depression 37 Type
  34. 34. with ❤from datarockets GraphQL API ● Schema => Types ● Resolvers 38
  35. 35. Part 1
  36. 36. Design of business layer
  37. 37. with ❤from datarockets GraphQL forces to isolate business logic 41
  38. 38. with ❤from datarockets 42 GraphQL forces to isolate business logic
  39. 39. with ❤from datarockets 43 GraphQL forces to isolate business logic
  40. 40. with ❤from datarockets 44 Queries
  41. 41. with ❤from datarockets Mutations 45
  42. 42. with ❤from datarockets What can be changed? 46
  43. 43. with ❤from datarockets Mutations 47
  44. 44. with ❤from datarockets 48
  45. 45. with ❤from datarockets Mutations 49
  46. 46. with ❤from datarockets Mutations 50 Trailblazer
  47. 47. with ❤from datarockets Mutations 51
  48. 48. with ❤from datarockets What could possibly go wrong? 52
  49. 49. with ❤from datarockets Mutations 53
  50. 50. with ❤from datarockets Expectation request query { me { items { id } } } 54 response { "data": { "me": { "items": [ { "id": "1" }, { "id": "2" }, // ... ] } }
  51. 51. with ❤from datarockets Reality request query { me { items { id } } } 55 response { "data": { "me": { "items": [ { "id": "MDEwOJlcG9zaXRcvnkzMDAxNzMzQA==" }, { "id": "MDEwOJlcG9zaXRcvnkzMDAxNjQ5Mg==" }, // ... ] } } } https://facebook.github.io/relay/graphql/objectidentification.html
  52. 52. Global Object Identification
  53. 53. with ❤from datarockets Mutations 57
  54. 54. with ❤from datarockets Mutations 58
  55. 55. with ❤from datarockets Summary ● GraphQL works really great if you follow Rails development best-practice ● You should remember and process GraphQL ID differently 59
  56. 56. Part 2
  57. 57. Common API issues
  58. 58. Pagination
  59. 59. with ❤from datarockets request query { me { items { id title } } } 63 response { "data": { "me": { "items": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" }, // and more 100500 items... ] } }
  60. 60. with ❤from datarockets What can we do here? 64
  61. 61. with ❤from datarockets 65
  62. 62. with ❤from datarockets request query { me { items(per_page: 2) { id title } } } 66 response { "data": { "me": { "items": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" } ] } } }
  63. 63. with ❤from datarockets How many items do we have? 67
  64. 64. with ❤from datarockets 68
  65. 65. with ❤from datarockets Do you like it? 69
  66. 66. with ❤from datarockets 70
  67. 67. with ❤from datarockets 71
  68. 68. with ❤from datarockets 72
  69. 69. with ❤from datarockets request query { me { items(first: 2) { nodes { id title } pageInfo { endCursor hasNextPage } } } } 73 response { "data": { "me": { "items": { "nodes": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" } ], "pageInfo": { "endCursor": "Y3Vyc29yOnYyOpHOAnq2TA==", "hasNextPage": true }
  70. 70. Authentication
  71. 71. with ❤from datarockets How we can make authentication? 75
  72. 72. with ❤from datarockets 76
  73. 73. with ❤from datarockets Using mutation ● Create a mutation which generates a token for access to the API ● It’s still may work for login/password authentication ● It would be harder to implement authentication via OAuth since we need to process redirects ● It’s hard to update all the data after successful authentication ● Maybe, this still makes sense. 77
  74. 74. with ❤from datarockets Choose approaches and solution according to your business cases and application reality 78
  75. 75. Authorization
  76. 76. with ❤from datarockets Delegate authorization logic to the business logic layer 80
  77. 77. with ❤from datarockets ● Authorize the user to perform some mutation ● Create per-field “helpers” for verifying access for making changes ● Scope data ● Get access to only some private fields 81
  78. 78. with ❤from datarockets Mutations authorization 82 somewhere here
  79. 79. with ❤from datarockets Exposing authorization rules in the API 83 request query { me { items(first: 2) { nodes { id canEdit } } } } response { "data": { "me": { "items": { "nodes": [ { "id": "1", "canEdit": true }, { "id": "2", "canEdit": false } ] }
  80. 80. with ❤from datarockets Scoping 84
  81. 81. with ❤from datarockets Field authorization request query { items { edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 85 response What is here?
  82. 82. with ❤from datarockets Field authorization request query { items { edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 86 response { "error": { "message": "Not Authorized" } }
  83. 83. with ❤from datarockets Field authorization request query { items { edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 87 response "data": { "items": { "edges": [ { "node": { "title": "Hello world", "description": "C++ in 21 days", "privateStatistic": null, } }, { "node": { "title": "Hello GraphQL", "description": "GraphQL in 35 minut "privateStatistic": { "viewerCount": 100500, "linkClicksCount": 0 },
  84. 84. with ❤from datarockets Field authorization request query { item(id: $id) { title description } } 88 response { "data": { "item": null } }
  85. 85. with ❤from datarockets Field authorization ● Nullable fields for controlling access to some fields ● The same result for not found and access denied errors ● No error messages on why we can’t get access to a field ● For collections we use null when user doesn’t have access and empty list [] if there are no items ● This is more about API design not about the implementation 89
  86. 86. N + 1 queries
  87. 87. with ❤from datarockets request query { items(first: 50) { nodes { id user { name } } } } 91 response { "data": { "items": { "nodes": [ { "id": "1", "user": { "name": "Vasya Pupkin" } }, { "id": "2", "user": { "name": "Ivan Ivanov" } }, // ... ]
  88. 88. with ❤from datarockets 92
  89. 89. with ❤from datarockets GraphQL::Batch 93 https://github.com/Shopify/graphql-batch
  90. 90. Cache
  91. 91. with ❤from datarockets Cache is hard? 96
  92. 92. with ❤from datarockets Cache is pain? 97
  93. 93. with ❤from datarockets field :user, Types::UserType, cache: {key: :user_id}, null: false 98 https://github.com/stackshareio/graphql-cache
  94. 94. Part 3
  95. 95. Powerful tips
  96. 96. Documentation
  97. 97. with ❤from datarockets GraphQL schema is the best documentation 102
  98. 98. with ❤from datarockets 103
  99. 99. with ❤from datarockets GraphiQL 104
  100. 100. with ❤from datarockets GraphiQL 105
  101. 101. with ❤from datarockets GraphiQL 106
  102. 102. with ❤from datarockets GraphiQL 107
  103. 103. with ❤from datarockets GraphQL Doc https://github.com/gjtorikian/graphql-docs 108
  104. 104. Field is a function
  105. 105. Field is a function resolver
  106. 106. with ❤from datarockets Field : GraphQL Type 112
  107. 107. with ❤from datarockets 113 request query { items(first: 50) { nodes { id user { name } } } item(id: "MDEwOJlcG9zaXRcvnkzMDAxNzMzQA==") { title } }
  108. 108. with ❤from datarockets Field : GraphQL Type Field : (arguments) => GraphQL Type 114
  109. 109. with ❤from datarockets 115 request query { items(first: 50) { nodes { id rawContent: content(format: RAW) content(format: MARKUP) } } }
  110. 110. Custom types
  111. 111. with ❤from datarockets Enums Types 117
  112. 112. with ❤from datarockets Scalar Types 118
  113. 113. Security
  114. 114. with ❤from datarockets 6 months ago 120
  115. 115. with ❤from datarockets 4 months ago 121
  116. 116. with ❤from datarockets What is wrong here? 122
  117. 117. with ❤from datarockets 123
  118. 118. with ❤from datarockets 124
  119. 119. with ❤from datarockets 125
  120. 120. with ❤from datarockets What about something unexpected ??? 126
  121. 121. with ❤from datarockets What about sql injection? 127 https://rails-sqli.org/
  122. 122. with ❤from datarockets 128 request query { items(first: 50, order: TITLE) { nodes { id title } } }
  123. 123. with ❤from datarockets Validate data and don’t trust users 129
  124. 124. with ❤from datarockets What about huge requests? 130
  125. 125. with ❤from datarockets Timeout https://graphql-ruby.org/queries/timeout.html 131
  126. 126. with ❤from datarockets Prevent deeply-nested queries https://graphql-ruby.org/queries/complexity_and_depth.html 132
  127. 127. with ❤from datarockets Prevent complex queries https://graphql-ruby.org/queries/complexity_and_depth.html 133
  128. 128. with ❤from datarockets Required pagination and limits 134
  129. 129. Part 4
  130. 130. Epilogue
  131. 131. with ❤from datarockets Summary ● GraphQL is a great process and care about all members of the team ● Graphql is a great convention for communication between developers ● It does not affect you business logic ● It resolver some issues and makes a new one ● Fun !!!! 137
  132. 132. with ❤from datarockets ● Subscription Types ● Input Types ● Working with IDs ● Visibility ● Supporting deprecated types and fields ● Converting GraphQL schema from AR schema ● Other approaches using GraphQL ● Using GraphQL queries with REST endpoint (e.g. Facebook API) ● Monitoring GraphQL schema ● Tests for GraphQL schema ● etc... 138
  133. 133. with ❤from datarockets ● Subscription Types ● Input Types ● Working with IDs ● Visibility ● Supporting deprecated types and fields ● Converting GraphQL schema from AR schema ● Other approaches using GraphQL ● Using GraphQL queries with REST endpoint (e.g. Graph API) ● Monitoring GraphQL schema ● Tests for GraphQL schema ● etc... 139🍻
  134. 134. Thank you! https://t.me/rdubrovsky https://github.com/roman-dubrovsky https://www.instagram.com/romandubrovsky https://git.io/Je457 with ❤ from datarockets
  135. 135. Enjoy what are you doing with ❤ from datarockets

×