with ❤from datarockets
Roman Dubrovsky
2
https://t.me/rdubrovsky
https://github.com/roman-dubrovsky
https://www.instagram.com/romandubrovsky
with ❤from datarockets 4
with ❤from datarockets 5
13:45 pm
with ❤from datarockets 6
13:45 pm
13:30 pm
with ❤from datarockets 7
with ❤from datarockets
Minsk
8
with ❤from datarockets
Minsk
9
Kiev
with ❤from datarockets
Minsk
10
Kiev
datarockets
https://datarockets.com
https://github.com/datarockets/career
https://www.instagram.com/datarockets
https://twitter.com/datarockets
https://www.facebook.com/datarockets
with ❤from datarockets
Minsk.rb
13
LIFE WITH GRAPHQL
API
GOOD PRACTICES AND UNRESOLVED ISSUES
with ❤ from datarockets
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
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
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
🍻
Part 0
GraphQL
with ❤from datarockets 20
Для тех кто в танке?
Шутка про минск?
Для тех кто в танке?
Шутка про минск?
with ❤from datarockets
Type
24
with ❤from datarockets
Fields
25
with ❤from datarockets
Field to another type
26
with ❤from datarockets
Thinking in Graphs
27
with ❤from datarockets
Where is logic?
28
with ❤from datarockets
Where do we store our logic?
29
with ❤from datarockets
Where do we store our logic?
Fields
30
with ❤from datarockets
Where do we store our logic?
Fields Resolvers
31
with ❤from datarockets
Query type
32
User
Organization
me
organization(id)
QueryType
with ❤from datarockets
Query type
33
QueryType
me
request
query {
me {
// ....
}
}
organization(id)
User
Organization
with ❤from datarockets
Mutation type
34
MutationType
CreatePost
PublishPost
createPost(postData)
publishPost(postId)
with ❤from datarockets 35
with ❤from datarockets
Typical depression
36
Type
with ❤from datarockets
Typical depression
37
Type
with ❤from datarockets
GraphQL API
● Schema => Types
● Resolvers
38
Part 1
Design of business layer
with ❤from datarockets
GraphQL forces to isolate business logic
41
with ❤from datarockets 42
GraphQL forces to isolate business logic
with ❤from datarockets 43
GraphQL forces to isolate business logic
with ❤from datarockets 44
Queries
with ❤from datarockets
Mutations
45
with ❤from datarockets
What can be changed?
46
with ❤from datarockets
Mutations
47
with ❤from datarockets 48
with ❤from datarockets
Mutations
49
with ❤from datarockets
Mutations
50
Trailblazer
with ❤from datarockets
Mutations
51
with ❤from datarockets
What could possibly go wrong?
52
with ❤from datarockets
Mutations
53
with ❤from datarockets
Expectation
request
query {
me {
items {
id
}
}
}
54
response
{
"data": {
"me": {
"items": [
{
"id": "1"
},
{
"id": "2"
},
// ...
]
}
}
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
Global Object
Identification
with ❤from datarockets
Mutations
57
with ❤from datarockets
Mutations
58
with ❤from datarockets
Summary
● GraphQL works really great if you follow Rails development best-practice
● You should remember and process GraphQL ID differently
59
Part 2
Common API issues
Pagination
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...
]
}
}
with ❤from datarockets
What can we do here?
64
with ❤from datarockets 65
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!!!"
}
]
}
}
}
with ❤from datarockets
How many items do we have?
67
with ❤from datarockets 68
with ❤from datarockets
Do you like it?
69
with ❤from datarockets 70
with ❤from datarockets 71
with ❤from datarockets 72
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
}
Authentication
with ❤from datarockets
How we can make authentication?
75
with ❤from datarockets 76
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
with ❤from datarockets
Choose approaches and solution
according to your business cases and
application reality
78
Authorization
with ❤from datarockets
Delegate authorization logic to the
business logic layer
80
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
with ❤from datarockets
Mutations authorization
82
somewhere here
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
}
]
}
with ❤from datarockets
Scoping
84
with ❤from datarockets
Field authorization
request
query {
items {
edges {
node {
title
description
privateStatistic {
viewerCount
linkClicksCount
}
}
}
}
}
85
response
What is here?
with ❤from datarockets
Field authorization
request
query {
items {
edges {
node {
title
description
privateStatistic {
viewerCount
linkClicksCount
}
}
}
}
}
86
response
{
"error": {
"message": "Not Authorized"
}
}
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
},
with ❤from datarockets
Field authorization
request
query {
item(id: $id) {
title
description
}
}
88
response
{
"data": {
"item": null
}
}
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
N + 1 queries
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"
}
},
// ...
]
with ❤from datarockets 92
with ❤from datarockets
GraphQL::Batch
93
https://github.com/Shopify/graphql-batch
Cache
with ❤from datarockets
Cache is hard?
96
with ❤from datarockets
Cache is pain?
97
with ❤from datarockets
field :user, Types::UserType, cache: {key: :user_id}, null: false
98
https://github.com/stackshareio/graphql-cache
Part 3
Powerful tips
Documentation
with ❤from datarockets
GraphQL schema is the best
documentation
102
with ❤from datarockets 103
with ❤from datarockets
GraphiQL
104
with ❤from datarockets
GraphiQL
105
with ❤from datarockets
GraphiQL
106
with ❤from datarockets
GraphiQL
107
with ❤from datarockets
GraphQL Doc
https://github.com/gjtorikian/graphql-docs
108
Field is a
function
Field is a
function resolver
with ❤from datarockets
Field : GraphQL Type
112
with ❤from datarockets 113
request
query {
items(first: 50) {
nodes {
id
user {
name
}
}
}
item(id: "MDEwOJlcG9zaXRcvnkzMDAxNzMzQA==") {
title
}
}
with ❤from datarockets
Field : GraphQL Type
Field : (arguments) => GraphQL Type
114
with ❤from datarockets 115
request
query {
items(first: 50) {
nodes {
id
rawContent: content(format: RAW)
content(format: MARKUP)
}
}
}
Custom types
with ❤from datarockets
Enums Types
117
with ❤from datarockets
Scalar Types
118
Security
with ❤from datarockets
6 months ago
120
with ❤from datarockets
4 months ago
121
with ❤from datarockets
What is wrong here?
122
with ❤from datarockets 123
with ❤from datarockets 124
with ❤from datarockets 125
with ❤from datarockets
What about something unexpected ???
126
with ❤from datarockets
What about sql injection?
127
https://rails-sqli.org/
with ❤from datarockets 128
request
query {
items(first: 50, order: TITLE) {
nodes {
id
title
}
}
}
with ❤from datarockets
Validate data and don’t trust users
129
with ❤from datarockets
What about huge requests?
130
with ❤from datarockets
Timeout
https://graphql-ruby.org/queries/timeout.html
131
with ❤from datarockets
Prevent deeply-nested queries
https://graphql-ruby.org/queries/complexity_and_depth.html
132
with ❤from datarockets
Prevent complex queries
https://graphql-ruby.org/queries/complexity_and_depth.html
133
with ❤from datarockets
Required pagination and limits
134
Part 4
Epilogue
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
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
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🍻
Thank you!
https://t.me/rdubrovsky
https://github.com/roman-dubrovsky
https://www.instagram.com/romandubrovsky
https://git.io/Je457
with ❤ from datarockets
Enjoy what are you doing
with ❤ from datarockets

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