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

Life with GraphQL

Life with GraphQL

Minsk.rb

Roman Dubrovsky

February 20, 2020
Tweet

More Decks by Roman Dubrovsky

Other Decks in Programming

Transcript

  1. 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 ❤ 8
  2. 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 9
  3. 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 10
  4. 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 • It was almost one year ago 11
  5. 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 • It was almost one year ago 12
  6. with ❤from datarockets Query type 32 QueryType me request query

    { me { // .... } } organization(id) User Organization
  7. with ❤from datarockets Expectation request query { me { items

    { id } } } 50 response { "data": { "me": { "items": [ { "id": "1" }, { "id": "2" }, // ... ] } }
  8. with ❤from datarockets Reality request query { me { items

    { id } } } 51 response { "data": { "me": { "items": [ { "id": "MDEwOJlcG9zaXRcvnkzMDAxNzMzQA==" }, { "id": "MDEwOJlcG9zaXRcvnkzMDAxNjQ5Mg==" }, // ... ] } } } https://facebook.github.io/relay/graphql/objectidentification.html
  9. with ❤from datarockets Summary • GraphQL works really great if

    you follow Rails development best-practice • You should remember and process GraphQL ID differently 55
  10. with ❤from datarockets request query { me { items {

    id title } } } 59 response { "data": { "me": { "items": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" }, // and more 100500 items... ] } }
  11. with ❤from datarockets request query { me { items(per_page: 2)

    { id title } } } 62 response { "data": { "me": { "items": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" } ] } } }
  12. with ❤from datarockets request query { me { items(first: 2)

    { nodes { id title } pageInfo { endCursor hasNextPage } } } } 69 response { "data": { "me": { "items": { "nodes": [ { "id": "1", "title": "Hello world!!!" }, { "id": "2", "title": "Hello GraphQL!!!" } ], "pageInfo": { "endCursor": "Y3Vyc29yOnYyOpHOAnq2TA==", "hasNextPage": true }
  13. 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. 73
  14. 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 77
  15. with ❤from datarockets Exposing authorization rules in the API 79

    request query { me { items(first: 2) { nodes { id canEdit } } } } response { "data": { "me": { "items": { "nodes": [ { "id": "1", "canEdit": true }, { "id": "2", "canEdit": false } ] }
  16. with ❤from datarockets Field authorization request query { items {

    edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 81 response What is here?
  17. with ❤from datarockets Field authorization request query { items {

    edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 82 response { "error": { "message": "Not Authorized" } }
  18. with ❤from datarockets Field authorization request query { items {

    edges { node { title description privateStatistic { viewerCount linkClicksCount } } } } } 83 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 },
  19. with ❤from datarockets Field authorization request query { item(id: $id)

    { title description } } 84 response { "data": { "item": null } }
  20. 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 85
  21. 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 • GraphQL spec knows how to resolve this issue but Ruby implementation does not. 86
  22. with ❤from datarockets request query { items(first: 50) { nodes

    { id user { name } } } } 89 response { "data": { "items": { "nodes": [ { "id": "1", "user": { "name": "Vasya Pupkin" } }, { "id": "2", "user": { "name": "Ivan Ivanov" } }, // ... ]
  23. with ❤from datarockets field :user, Types::UserType, cache: {key: :user_id}, null:

    false 96 https://github.com/stackshareio/graphql-cache
  24. with ❤from datarockets Query type 108 QueryType me request query

    { me { // .... } } organization(id) User Organization
  25. with ❤from datarockets 111 request query { items(first: 50) {

    nodes { id user { name } } } item(id: "MDEwOJlcG9zaXRcvnkzMDAxNzMzQA==") { title } }
  26. with ❤from datarockets 113 request query { items(first: 50) {

    nodes { id rawContent: content(format: RAW) content(format: MARKUP) } } }
  27. 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 • No worries about formats and versioning • Fun !!!! 136
  28. 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... 137
  29. 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... 138