What/how to do with GraphQL?
Valentyn Ostakh
#27
query {
me {
firstName
lastName
company
position
socialLinks {
name
url
}
}
}
{
"data": {
"me": {
"firstName": "Valentyn",
"lastName": "Ostakh",
"company": "RubyGarage",
"position": "Ruby/JS developer",
"socialLinks": [
{
"name": "facebook",
"url": "https://facebook.com/valikos"
},
{
"name": "twitter",
"url": "https://twitter.com/valikos_ost"
},
{
"name": "github",
"url": "https://github.com/valikos"
}
]
}
}
}
Agenda
• Introduction into GraphQL

• GraphQL SDL(Schema Definition Language)

• GraphQL Execution

• Pitfalls
What is
GraphQL?
🤔
What is GraphQL?
• A query language for API

• A type system of defined data

• A platform of both backend + frontend applications
More About GraphQL
• GraphQL was developed internally by Facebook in 2012 before being
publicly released in 2015

• The idea of GraphQL became from the frontend team

• GraphQL services can be written in any language

• GraphQL is transport-agnostic

• GraphQL represents data in graphs
GraphQL SDL
What to do with GraphQL?
🗺
GraphQL SDL
GraphQL schema is at the center of any GraphQL server
implementation.

GraphQL schema describes the functionality available to the
clients who connect to it
GraphQL SDL
• Schema

• Object Types

• Fields

• Scalars

• Enums

• Lists

• Non-Null
• Directives

• Aliases

• Interfaces

• Unions

• Fragments

• Input Objects
Object Type
GraphQL Object Type
{
"data": {
"character": {
"firstName": "Peter",
"lastName": "Griffin",
"friends": [
{
"firstName": "Brian",
"lastName": null
},
{
"firstName": "Homer",
"lastName": "Simpson"
}
]
}
}
}
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Object Type
{
"data": {
"character": {
"firstName": "Peter",
"lastName": "Griffin",
"friends": [
{
"firstName": "Brian",
"lastName": null
},
{
"firstName": "Homer",
"lastName": "Simpson"
}
]
}
}
}
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Object Type
type Character {
firstName: String!
lastName: String
friends: [Character!]
}
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :friends, [Types::CharacterType], null: true
end
end
Fields
GraphQL Fields
type Character {
firstName: String!
lastName: String
friends: [Character!]
}
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :friends, [Types::CharacterType], null: true
end
end
GraphQL Fields
{
"data": {
"character": {
"firstName": "Peter",
"lastName": "Griffin",
"friends": [
{
"firstName": "Brian",
"lastName": null
},
{
"firstName": "Homer",
"lastName": "Simpson"
}
]
}
}
}
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Fields
{
"data": {
"character": {
"firstName": "Peter",
"lastName": "Griffin",
"friends": [
{
"firstName": "Brian",
"lastName": null
},
{
"firstName": "Homer",
"lastName": "Simpson"
}
]
}
}
}
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Fields
• Arguments

• Resolvers
GraphQL Fields: Arguments
{
"data": {
"character": {
"firstName": "Jon",
"lastName": "wonS",
"friends": [
{
"firstName": "Samwell",
"lastName": "Tarly"
}
]
}
}
}
query {
character {
firstName
lastName(reverse: true)
friends(last: 1) {
firstName
lastName
}
}
}
GraphQL Fields: Arguments
{
"data": {
"character": {
"firstName": "Jon",
"lastName": "wonS",
"friends": [
{
"firstName": "Samwell",
"lastName": "Tarly"
}
]
}
}
}
query {
character {
firstName
lastName(reverse: true)
friends(last: 1) {
firstName
lastName
}
}
}
GraphQL Fields: Arguments
type Character {
firstName: String!
lastName(reverse: Boolean): String
friends(last: Int): [Character!]
}
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true do
argument :reverse, Boolean, required: false
end
field :friends, [Types::CharacterType], null: true do
argument :last, Integer, required: false
end
end
end
GraphQL Fields: Arguments
type Character {
firstName: String!
lastName(reverse: Boolean): String
friends(last: Int): [Character!]
}
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true do
argument :reverse, Boolean, required: false
end
field :friends, [Types::CharacterType], null: true do
argument :last, Integer, required: false
end
end
end
GraphQL Fields: Resolvers
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :full_name, String, null: false
end
end
GraphQL Fields: Resolvers
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :full_name, String, null: false
def full_name
[object.full_name, object.last_name].join(' ')
end
end
end
GraphQL Fields: Resolvers
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :full_name, String, null: false, resolver: Resolvers::FullName
end
end
GraphQL Fields: Resolvers
module Resolvers
class Character < Resolvers::Base
type Character, null: false
argument :id, ID, required: true
def resolve(id:)
Character.find(id)
end
end
end
Scalars
GraphQL Scalars
A GraphQL object type has a name and fields
but at some point those fields have to
become some concrete data. 

That's where the scalar types come in: they
represent the leaves of the query.
GraphQL Scalars: Built-in Types
• Int: A signed 32‐bit integer

• Float: A signed double-precision floating-point value

• String: A UTF‐8 character sequence

• Boolean: true or false

• ID: The ID scalar type represents a unique identifier, often used to
refetch an object or as the key for a cache. The ID type is
serialized in the same way as a String; however, defining it as
an ID signifies that it is not intended to be human‐readable
GraphQL Scalars
In most GraphQL service implementations,
there is also a way to specify custom scalar
types.
GraphQL Scalars: GraphQL-Ruby Scalar Types
• Int: like a JSON or Ruby integer

• Float: like a JSON or Ruby floating point decimal

• String: like a JSON or Ruby string

• Boolean: like a JSON or Ruby boolean (true or false)

• ID: which a specialized String for representing unique object
identifiers

• ISO8601DateTime: an ISO 8601-encoded datetime
GraphQL Scalars: Custom Scalar
class Types::Url < Types::BaseScalar
description "A valid URL, transported as a string"
def self.coerce_input(input_value, context)
url = URI.parse(input_value)
if url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS)
url
else
raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid URL"
end
end
def self.coerce_result(ruby_value, context)
ruby_value.to_s
end
end
GraphQL Scalars: Custom Scalar
class Types::Url < Types::BaseScalar
description "A valid URL, transported as a string"
def self.coerce_input(input_value, context)
url = URI.parse(input_value)
if url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS)
url
else
raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid URL"
end
end
def self.coerce_result(ruby_value, context)
ruby_value.to_s
end
end
Enums
GraphQL Enums
Enumerations are similar to custom scalars with the limitation that their
values can only be one of a pre-defined list of strings.
GraphQL Enums
{
"data": {
"character": {
"firstName": "Peter",
"role": "FATHER",
"friends": [
{
"firstName": "Brian",
"role": "PET"
},
{
"firstName": "Stewie",
"role": "SON"
}
]
}
}
}
query {
character {
firstName
role
friends {
firstName
role
}
}
}
GraphQL Enums
enum RoleEnum {
FATHER
MOTHER
SON
DAUGHTER
DOG
}
class Types::RoleEnum < Types::BaseEnum
value ‘FATHER'
value ‘MOTHER'
value ‘SON'
value ‘DAUGHTER'
value ‘PET'
end
GraphQL Enums
enum RoleEnum {
FATHER
MOTHER
SON
DAUGHTER
DOG
}
class Types::RoleEnum < Types::BaseEnum
value 'FATHER', value: 1
value 'MOTHER', value: 2
value 'SON', value: 3
value 'DAUGHTER', value: 4
value 'PET', value: 5
end
GraphQL Enums
enum RoleEnum {
FATHER
MOTHER
SON
DAUGHTER
DOG
}
class Types::RoleEnum < Types::BaseEnum
value 'FATHER', value: :father
value 'MOTHER', value: :mom
value 'SON', value: :son
value 'DAUGHTER', value: :daughter
value 'PET', value: :animal
end
Lists
GraphQL Lists
{
"data": {
"character": {
"firstName": "Peter",
"lastName": "Griffin",
"friends": [
{
"firstName": "Brian",
"lastName": null
},
{
"firstName": "Homer",
"lastName": "Simpson"
}
]
}
}
}
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Lists
type Character {
firstName: String!
lastName: String
friends: [Character!]
}
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :friends, [Types::CharacterType], null: true
end
end
Non-Null
GraphQL Non-Null
In the GraphQL type system all types are nullable by default. 

This means that a type like Int can take any integer (1, 2, etc.)
or null which represents the absence of any value. 

However, the GraphQL type system allows you to make any type non-
null which means that the type will never produce a null value. 

When using a non-null type there will always be a value.
GraphQL Non-Null
type Character {
firstName: String!
lastName: String
friends: [Character!]!
}
type Character {
firstName: String!
lastName: String
friends: [Character]!
}
type Character {
firstName: String!
lastName: String
friends: [Character!]
}
type Character {
firstName: String!
lastName: String
friends: [Character]
}
GraphQL Non-Null
module Types
class CharacterType < BaseObject
field :first_name, String, null: false
field :last_name, String, null: true
field :friends, [Types::CharacterType, null: true], null: true
field :friends, [Types::CharacterType, null: true], null: false
field :friends, [Types::CharacterType, null: false], null: true
field :friends, [Types::CharacterType, null: false], null: false
end
end
Unions
GraphQL Unions
{
search(in: "Adventure Time") {
__typename
... on Character {
firstName
}
... on land {
name
}
... on Building {
type
}
}
}
{
"data": {
"search": [
{
"__typename": "Character",
"firstName": "Finn"
},
{
"__typename": "Land",
"name": "Land of Ooo"
},
{
"__typename": "Building",
"type": "Fort"
}
]
}
}
GraphQL Unions
union Result = Character | Land | Building
type Character {
firstName: String!
}
type Building {
type: String!
}
type Land {
name: String!
}
type Query {
search: [Result]
}
GraphQL Unions
union Result = Character | Land | Building
type Character {
firstName: String!
}
type Building {
type: String!
}
type Land {
name: String!
}
type Query {
search: [Result]
}
GraphQL Unions
class Types::ResultType < Types::BaseUnion
possible_types Types::CharacterType, Types::LandType, Types::BuildingType
# Optional: if this method is defined, it will override `Schema.resolve_type`
def self.resolve_type(object, context)
if object.is_a?(Character)
Types::CharacterType
elsif object.is_a?(Land)
Types::LandType
else
Types::BuildingType
end
end
end
Interfaces
GraphQL Interfaces
interface Node {
id: ID!
}
interface Person {
firstName: String!
lastName: String
}
type Land implements Node {
id: ID!
name: String!
}
type Character implements Node & Person {
id: ID!
firstName: String!
lastName: String
}
GraphQL Interfaces
module Types::Interfaces::Node
include Types::BaseInterface
field :id, ID, null: false
end
module Types::Interfaces::Person
include Types::BaseInterface
field :first_name, String, null: false
field :last_name, String, null: true
end
module Types
class CharacterType < BaseObject
implements Types::Interfaces::Node
implements Types::Interfaces::Person
end
end
Fragments
GraphQL Fragments
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Fragments
fragment CharacterFragment on Character {
firstName
lastName
}
query {
character {
...CharacterFragment
friends {
...CharacterFragment
}
}
}
Aliases
GraphQL Aliases
query {
hero: character(hero: true) {
firstName
}
antihero: character(hero: false) {
firstName
}
}
{
"data": {
"hero": {
"firstName": "Harrison",
},
"antihero": {
"firstName": "Sebastian",
}
}
}
Directives
GraphQL Directives
• @deprecated(reason: String) - marks fields as deprecated with messages

• @skip(if: Boolean!) - GraphQL execution skips the field if true by not calling the resolver

• @include(id: Boolean!) - Calls resolver for annotated field if true
GraphQL provides several built-in directives:
GraphQL Directives
query {
character {
firstName
lastName
friends @skip(if: $isAlone){
firstName
lastName
}
}
}
type Character {
firstName: String!
lastName: String
surname: String @deprecated(reason: "Use lastName. Will be removed...")
friends: [Character!]
}
GraphQL Directives: Custom Directive
class Directives::Rest < GraphQL::Schema::Directive
description "..."
locations(
GraphQL::Schema::Directive::FIELD,
GraphQL::Schema::Directive::FRAGMENT_SPREAD,
GraphQL::Schema::Directive::INLINE_FRAGMENT
)
argument :url, String, required: true, description: "..."
def self.include?(obj, args, ctx)
# implementation
end
def self.resolve(obj, args, ctx)
# implementation
end
end
query {
character @rest(url: "/path") {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL Directives: Custom Directive
Input Objects
GraphQL Input Objects
mutation CreateCharacter(
$firstName: String!
$lastName: String
$role: RoleEnum!
) {
createCharacter(
firstName: $firstName
lastName: $lastName
role: $role
) {
firstName
lastName
role
}
}
mutation CreateCharacter(
$input: CharacterAttributes!
) {
createCharacter(input: $input) {
firstName
lastName
role
}
}
GraphQL Input Objects
input CharacterAttributes {
firstName: String!
lastName: String
role: RoleEnum!
}
class Types::CharacterAttributes < Types::BaseInputObject
argument :first_name, String, required: true
argument :last_name, String, required: false
argument :role, Types::RoleEnum, required: false
end
Schema
🍒
GraphQL Schema
schema {
query: Query
}
GraphQL Schema
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
class MySchema < GraphQL::Schema
# Required:
query Types::QueryType
# Optional:
mutation Types::MutationType
subscription Types::SubscriptionType
end
GraphQL Schema
class Types::QueryType < GraphQL::Schema::Object
field :character, Types::CharacterType, resolver: Resolvers::Character
end
# Similarly:
class Types::MutationType < GraphQL::Schema::Object
# ...
end
# and
class Types::SubscriptionType < GraphQL::Schema::Object
# ...
end
type Query {
character(id: ID!): CharacterType
}
What GraphQL SDL gives us?
What GraphQL SDL gives us?
Documentation
What GraphQL SDL gives us?
Documentation is the first class citizen in GraphQL
GraphQL Execution
How to do with GraphQL?
🚀
When executing a GraphQL query one of the very first things the server needs to do
is transform the query (currently a string) into something it understands.
Transport
Transport
• HTTP POST

• one endpoint (e.g. /graphql)

• response code 200 OK
Transport
GraphQL-Ruby Phases of Execution
• Tokenize: splits the string into a stream of tokens

• Parse: builds an abstract syntax tree (AST) out of the stream of tokens

• Validate: validates the incoming AST as a valid query for the schema

• Rewrite: builds a tree of nodes which express the query in a simpler way than the
AST

• Analyze: if there are any query analyzers, they are run

• Execute: the query is traversed, resolve functions are called and the response is built

• Respond: the response is returned as a Hash
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
Tokenize & Parsing
GraphQL has its own grammar.

We need this rules to split up the query.

 GraphQL Ruby uses a tool called Ragel to generate its lexer.
How to understand that we have valid data?
How to verify incoming data?
• Breaks up a stream of characters (in our case a GraphQL query) into
tokens

• Turns sequences of tokens into a more abstract representation of the
language
Lexer
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL.scan(query) =>
[
(QUERY "query" [2:1]),
(LCURLY "{" [2:7]),
(IDENTIFIER "character" [3:3]),
(LCURLY "{" [3:13]),
(IDENTIFIER "firstName" [4:5]),
(IDENTIFIER "lastName" [5:5]),
(IDENTIFIER "friends" [6:5]),
(LCURLY "{" [6:13]),
(IDENTIFIER "firstName" [7:7]),
(IDENTIFIER "lastName" [8:7]),
(RCURLY "}" [9:5]),
(RCURLY "}" [10:3]),
(RCURLY "}" [11:1])
]
Parser
query {
character {
firstName
lastName
friends {
firstName
lastName
}
}
}
GraphQL.parse(query) =>
#<GraphQL::Language::Nodes::Document:0x00007fbd8ae3dec0
@definitions=
[#<GraphQL::Language::Nodes::OperationDefinition:…
@col=1,
@directives=[],
@filename=nil,
@line=2,
@name=nil,
@operation_type="query",
@selections=
[#<GraphQL::Language::Nodes::Field:…
@alias=nil,
@arguments=[],
@col=3,
@directives=[],
@filename=nil,
@line=3,
@name="character"
Lexer & Parser
Javascript implementation of GraphQL has hand-written lexer and parser.

GraphQL Ruby uses a tool called Ragel to generate its lexer.

GraphQL Ruby uses a tool called Racc to generate its parser.
GraphQL-Ruby Phases of Execution
Tokenizing and Parsing are fundamental steps in the execution process.

Validating, Rewriting, Analyzing, Executing are just details of the implementation.
Pitfalls
🤕
Pitfalls
• Authentication

• File uploading

• N+1

• Caching

• Performance
Authentication
• One endpoint

• Handle guests and registered users

• Fetch schema definition

• Solutions:

1. auth processes with GraphQL

2. auth by tokens (JWT, OAuth) (check tokens)
File uploading
• Vanilla GraphQL doesn’t support throwing raw files into your mutations

• Solutions:

1. Base64 Encoding

2. Separate Upload Requests

3. GraphQL Multipart Requests(most recommended)
N+1
• The server executes multiple unnecessary round trips to data stores for
nested data

• Problem in how GraphQL works, not Ruby

• Solutions:

1. preload data

2. gem ‘graphql-batch’

3. gem ‘batch-loader’
Caching
• Transport-agnostic

• Uses POST with HTTP

• Don’t have url with identifier

• Solution:

1. Server side caching(Memcache, Redis, etc.)
Performance
• Big queries can bring your server down to its knees

• Solutions:

1. Set query timeout

2. Check query depth

3. Check query complexity
Links
• https://graphql.org

• https://gql.foundation

• https://graphql.github.io/graphql-spec

• https://graphql-ruby.org

• https://github.com/valikos/rm-27
Thanks
🙌
Questions?
🤔

More Related Content

PDF
Json at work overview and ecosystem-v2.0
PDF
GraphQL & Relay - 串起前後端世界的橋樑
PPT
Javascript2839
PDF
Json the-x-in-ajax1588
PDF
Jsonsaga 100605143125-phpapp02
PPT
J s-o-n-120219575328402-3
ODP
Terms of endearment - the ElasticSearch Query DSL explained
PDF
Neo4j Introduction (Basics, Cypher, RDBMS to GRAPH)
Json at work overview and ecosystem-v2.0
GraphQL & Relay - 串起前後端世界的橋樑
Javascript2839
Json the-x-in-ajax1588
Jsonsaga 100605143125-phpapp02
J s-o-n-120219575328402-3
Terms of endearment - the ElasticSearch Query DSL explained
Neo4j Introduction (Basics, Cypher, RDBMS to GRAPH)

What's hot (20)

PDF
Automatically generating-json-from-java-objects-java-objects268
PDF
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
PDF
Modelling Data as Graphs (Neo4j)
PDF
Scala In The Wild
PPTX
Cutting through the fog of microservices: lightsabers optional
PPTX
ETL into Neo4j
PDF
Introduction to JSON & Ajax
PPTX
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
PPT
Why Java Needs Hierarchical Data
PPTX
Building Next-Generation Web APIs with JSON-LD and Hydra
PDF
Использование Elasticsearch для организации поиска по сайту
PPTX
Graph and RDF databases
PPTX
Amsterdam museum as five star linked data
PDF
The Gremlin in the Graph
PPT
Json - ideal for data interchange
KEY
JSON-LD: JSON for Linked Data
KEY
JSON-LD and MongoDB
PDF
Linked Data in Use: Schema.org, JSON-LD and hypermedia APIs - Front in Bahia...
PDF
It's 2017, and I still want to sell you a graph database
PDF
Computational Social Science, Lecture 09: Data Wrangling
Automatically generating-json-from-java-objects-java-objects268
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
Modelling Data as Graphs (Neo4j)
Scala In The Wild
Cutting through the fog of microservices: lightsabers optional
ETL into Neo4j
Introduction to JSON & Ajax
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
Why Java Needs Hierarchical Data
Building Next-Generation Web APIs with JSON-LD and Hydra
Использование Elasticsearch для организации поиска по сайту
Graph and RDF databases
Amsterdam museum as five star linked data
The Gremlin in the Graph
Json - ideal for data interchange
JSON-LD: JSON for Linked Data
JSON-LD and MongoDB
Linked Data in Use: Schema.org, JSON-LD and hypermedia APIs - Front in Bahia...
It's 2017, and I still want to sell you a graph database
Computational Social Science, Lecture 09: Data Wrangling
Ad

Similar to What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27 (20)

PDF
Overview of GraphQL & Clients
PDF
Better APIs with GraphQL
PDF
The Serverless GraphQL Backend Architecture
PDF
GraphQL Subscriptions
PDF
HyperGraphQL
PPT
Advanced Json
PDF
Next-generation API Development with GraphQL and Prisma
PDF
GraphQL - when REST API is not enough - lessons learned
PDF
GraphQL - when REST API is to less - lessons learned
PDF
GraphQL - when REST API is to less - lessons learned
PPTX
Copy/paste detector for source code on javascript
PDF
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
PDF
GraphQL - gdy API RESTowe to za mało
PDF
Leveraging the Power of Graph Databases in PHP
PDF
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
PDF
06. ElasticSearch : Mapping and Analysis
PDF
Harnessing The Power of Search - Liferay DEVCON 2015, Darmstadt, Germany
PDF
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
PDF
d3sparql.js demo at SWAT4LS 2014 in Berlin
PDF
[DevCrowd] GraphQL - gdy API RESTowe to za mało
Overview of GraphQL & Clients
Better APIs with GraphQL
The Serverless GraphQL Backend Architecture
GraphQL Subscriptions
HyperGraphQL
Advanced Json
Next-generation API Development with GraphQL and Prisma
GraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is to less - lessons learned
GraphQL - when REST API is to less - lessons learned
Copy/paste detector for source code on javascript
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
GraphQL - gdy API RESTowe to za mało
Leveraging the Power of Graph Databases in PHP
Max Neunhöffer – Joins and aggregations in a distributed NoSQL DB - NoSQL mat...
06. ElasticSearch : Mapping and Analysis
Harnessing The Power of Search - Liferay DEVCON 2015, Darmstadt, Germany
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
d3sparql.js demo at SWAT4LS 2014 in Berlin
[DevCrowd] GraphQL - gdy API RESTowe to za mało
Ad

More from Ruby Meditation (20)

PDF
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
PDF
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
PDF
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
PDF
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
PDF
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
PDF
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
PDF
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
PDF
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
PDF
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
PDF
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
PDF
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
PDF
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
PDF
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
PDF
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
PDF
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
PDF
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
PDF
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
PDF
Rails App performance at the limit - Bogdan Gusiev
PDF
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
PDF
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Rails App performance at the limit - Bogdan Gusiev
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
Postgres vs Elasticsearch while enriching data - Vlad Somov | Ruby Meditaiton...

Recently uploaded (20)

PDF
giants, standing on the shoulders of - by Daniel Stenberg
PDF
Auditboard EB SOX Playbook 2023 edition.
PDF
Comparative analysis of machine learning models for fake news detection in so...
PPTX
agenticai-neweraofintelligence-250529192801-1b5e6870.pptx
PPTX
Internet of Everything -Basic concepts details
PDF
CXOs-Are-you-still-doing-manual-DevOps-in-the-age-of-AI.pdf
PDF
Improvisation in detection of pomegranate leaf disease using transfer learni...
PDF
MENA-ECEONOMIC-CONTEXT-VC MENA-ECEONOMIC
PDF
“The Future of Visual AI: Efficient Multimodal Intelligence,” a Keynote Prese...
PDF
Accessing-Finance-in-Jordan-MENA 2024 2025.pdf
PPTX
SGT Report The Beast Plan and Cyberphysical Systems of Control
PDF
Connector Corner: Transform Unstructured Documents with Agentic Automation
PDF
Convolutional neural network based encoder-decoder for efficient real-time ob...
PPTX
GROUP4NURSINGINFORMATICSREPORT-2 PRESENTATION
PDF
Dell Pro Micro: Speed customer interactions, patient processing, and learning...
PDF
Transform-Your-Streaming-Platform-with-AI-Driven-Quality-Engineering.pdf
PDF
Aug23rd - Mulesoft Community Workshop - Hyd, India.pdf
PDF
A hybrid framework for wild animal classification using fine-tuned DenseNet12...
PPTX
Training Program for knowledge in solar cell and solar industry
PDF
SaaS reusability assessment using machine learning techniques
giants, standing on the shoulders of - by Daniel Stenberg
Auditboard EB SOX Playbook 2023 edition.
Comparative analysis of machine learning models for fake news detection in so...
agenticai-neweraofintelligence-250529192801-1b5e6870.pptx
Internet of Everything -Basic concepts details
CXOs-Are-you-still-doing-manual-DevOps-in-the-age-of-AI.pdf
Improvisation in detection of pomegranate leaf disease using transfer learni...
MENA-ECEONOMIC-CONTEXT-VC MENA-ECEONOMIC
“The Future of Visual AI: Efficient Multimodal Intelligence,” a Keynote Prese...
Accessing-Finance-in-Jordan-MENA 2024 2025.pdf
SGT Report The Beast Plan and Cyberphysical Systems of Control
Connector Corner: Transform Unstructured Documents with Agentic Automation
Convolutional neural network based encoder-decoder for efficient real-time ob...
GROUP4NURSINGINFORMATICSREPORT-2 PRESENTATION
Dell Pro Micro: Speed customer interactions, patient processing, and learning...
Transform-Your-Streaming-Platform-with-AI-Driven-Quality-Engineering.pdf
Aug23rd - Mulesoft Community Workshop - Hyd, India.pdf
A hybrid framework for wild animal classification using fine-tuned DenseNet12...
Training Program for knowledge in solar cell and solar industry
SaaS reusability assessment using machine learning techniques

What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27

  • 1. What/how to do with GraphQL? Valentyn Ostakh #27
  • 2. query { me { firstName lastName company position socialLinks { name url } } } { "data": { "me": { "firstName": "Valentyn", "lastName": "Ostakh", "company": "RubyGarage", "position": "Ruby/JS developer", "socialLinks": [ { "name": "facebook", "url": "https://facebook.com/valikos" }, { "name": "twitter", "url": "https://twitter.com/valikos_ost" }, { "name": "github", "url": "https://github.com/valikos" } ] } } }
  • 3. Agenda • Introduction into GraphQL • GraphQL SDL(Schema Definition Language) • GraphQL Execution • Pitfalls
  • 5. What is GraphQL? • A query language for API • A type system of defined data • A platform of both backend + frontend applications
  • 6. More About GraphQL • GraphQL was developed internally by Facebook in 2012 before being publicly released in 2015 • The idea of GraphQL became from the frontend team • GraphQL services can be written in any language • GraphQL is transport-agnostic • GraphQL represents data in graphs
  • 7. GraphQL SDL What to do with GraphQL? 🗺
  • 8. GraphQL SDL GraphQL schema is at the center of any GraphQL server implementation. GraphQL schema describes the functionality available to the clients who connect to it
  • 9. GraphQL SDL • Schema • Object Types • Fields • Scalars • Enums • Lists • Non-Null • Directives • Aliases • Interfaces • Unions • Fragments • Input Objects
  • 11. GraphQL Object Type { "data": { "character": { "firstName": "Peter", "lastName": "Griffin", "friends": [ { "firstName": "Brian", "lastName": null }, { "firstName": "Homer", "lastName": "Simpson" } ] } } } query { character { firstName lastName friends { firstName lastName } } }
  • 12. GraphQL Object Type { "data": { "character": { "firstName": "Peter", "lastName": "Griffin", "friends": [ { "firstName": "Brian", "lastName": null }, { "firstName": "Homer", "lastName": "Simpson" } ] } } } query { character { firstName lastName friends { firstName lastName } } }
  • 13. GraphQL Object Type type Character { firstName: String! lastName: String friends: [Character!] } module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :friends, [Types::CharacterType], null: true end end
  • 15. GraphQL Fields type Character { firstName: String! lastName: String friends: [Character!] } module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :friends, [Types::CharacterType], null: true end end
  • 16. GraphQL Fields { "data": { "character": { "firstName": "Peter", "lastName": "Griffin", "friends": [ { "firstName": "Brian", "lastName": null }, { "firstName": "Homer", "lastName": "Simpson" } ] } } } query { character { firstName lastName friends { firstName lastName } } }
  • 17. GraphQL Fields { "data": { "character": { "firstName": "Peter", "lastName": "Griffin", "friends": [ { "firstName": "Brian", "lastName": null }, { "firstName": "Homer", "lastName": "Simpson" } ] } } } query { character { firstName lastName friends { firstName lastName } } }
  • 19. GraphQL Fields: Arguments { "data": { "character": { "firstName": "Jon", "lastName": "wonS", "friends": [ { "firstName": "Samwell", "lastName": "Tarly" } ] } } } query { character { firstName lastName(reverse: true) friends(last: 1) { firstName lastName } } }
  • 20. GraphQL Fields: Arguments { "data": { "character": { "firstName": "Jon", "lastName": "wonS", "friends": [ { "firstName": "Samwell", "lastName": "Tarly" } ] } } } query { character { firstName lastName(reverse: true) friends(last: 1) { firstName lastName } } }
  • 21. GraphQL Fields: Arguments type Character { firstName: String! lastName(reverse: Boolean): String friends(last: Int): [Character!] } module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true do argument :reverse, Boolean, required: false end field :friends, [Types::CharacterType], null: true do argument :last, Integer, required: false end end end
  • 22. GraphQL Fields: Arguments type Character { firstName: String! lastName(reverse: Boolean): String friends(last: Int): [Character!] } module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true do argument :reverse, Boolean, required: false end field :friends, [Types::CharacterType], null: true do argument :last, Integer, required: false end end end
  • 23. GraphQL Fields: Resolvers module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :full_name, String, null: false end end
  • 24. GraphQL Fields: Resolvers module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :full_name, String, null: false def full_name [object.full_name, object.last_name].join(' ') end end end
  • 25. GraphQL Fields: Resolvers module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :full_name, String, null: false, resolver: Resolvers::FullName end end
  • 26. GraphQL Fields: Resolvers module Resolvers class Character < Resolvers::Base type Character, null: false argument :id, ID, required: true def resolve(id:) Character.find(id) end end end
  • 28. GraphQL Scalars A GraphQL object type has a name and fields but at some point those fields have to become some concrete data. That's where the scalar types come in: they represent the leaves of the query.
  • 29. GraphQL Scalars: Built-in Types • Int: A signed 32‐bit integer • Float: A signed double-precision floating-point value • String: A UTF‐8 character sequence • Boolean: true or false • ID: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable
  • 30. GraphQL Scalars In most GraphQL service implementations, there is also a way to specify custom scalar types.
  • 31. GraphQL Scalars: GraphQL-Ruby Scalar Types • Int: like a JSON or Ruby integer • Float: like a JSON or Ruby floating point decimal • String: like a JSON or Ruby string • Boolean: like a JSON or Ruby boolean (true or false) • ID: which a specialized String for representing unique object identifiers • ISO8601DateTime: an ISO 8601-encoded datetime
  • 32. GraphQL Scalars: Custom Scalar class Types::Url < Types::BaseScalar description "A valid URL, transported as a string" def self.coerce_input(input_value, context) url = URI.parse(input_value) if url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS) url else raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid URL" end end def self.coerce_result(ruby_value, context) ruby_value.to_s end end
  • 33. GraphQL Scalars: Custom Scalar class Types::Url < Types::BaseScalar description "A valid URL, transported as a string" def self.coerce_input(input_value, context) url = URI.parse(input_value) if url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS) url else raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid URL" end end def self.coerce_result(ruby_value, context) ruby_value.to_s end end
  • 34. Enums
  • 35. GraphQL Enums Enumerations are similar to custom scalars with the limitation that their values can only be one of a pre-defined list of strings.
  • 36. GraphQL Enums { "data": { "character": { "firstName": "Peter", "role": "FATHER", "friends": [ { "firstName": "Brian", "role": "PET" }, { "firstName": "Stewie", "role": "SON" } ] } } } query { character { firstName role friends { firstName role } } }
  • 37. GraphQL Enums enum RoleEnum { FATHER MOTHER SON DAUGHTER DOG } class Types::RoleEnum < Types::BaseEnum value ‘FATHER' value ‘MOTHER' value ‘SON' value ‘DAUGHTER' value ‘PET' end
  • 38. GraphQL Enums enum RoleEnum { FATHER MOTHER SON DAUGHTER DOG } class Types::RoleEnum < Types::BaseEnum value 'FATHER', value: 1 value 'MOTHER', value: 2 value 'SON', value: 3 value 'DAUGHTER', value: 4 value 'PET', value: 5 end
  • 39. GraphQL Enums enum RoleEnum { FATHER MOTHER SON DAUGHTER DOG } class Types::RoleEnum < Types::BaseEnum value 'FATHER', value: :father value 'MOTHER', value: :mom value 'SON', value: :son value 'DAUGHTER', value: :daughter value 'PET', value: :animal end
  • 40. Lists
  • 41. GraphQL Lists { "data": { "character": { "firstName": "Peter", "lastName": "Griffin", "friends": [ { "firstName": "Brian", "lastName": null }, { "firstName": "Homer", "lastName": "Simpson" } ] } } } query { character { firstName lastName friends { firstName lastName } } }
  • 42. GraphQL Lists type Character { firstName: String! lastName: String friends: [Character!] } module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :friends, [Types::CharacterType], null: true end end
  • 44. GraphQL Non-Null In the GraphQL type system all types are nullable by default. This means that a type like Int can take any integer (1, 2, etc.) or null which represents the absence of any value. However, the GraphQL type system allows you to make any type non- null which means that the type will never produce a null value. When using a non-null type there will always be a value.
  • 45. GraphQL Non-Null type Character { firstName: String! lastName: String friends: [Character!]! } type Character { firstName: String! lastName: String friends: [Character]! } type Character { firstName: String! lastName: String friends: [Character!] } type Character { firstName: String! lastName: String friends: [Character] }
  • 46. GraphQL Non-Null module Types class CharacterType < BaseObject field :first_name, String, null: false field :last_name, String, null: true field :friends, [Types::CharacterType, null: true], null: true field :friends, [Types::CharacterType, null: true], null: false field :friends, [Types::CharacterType, null: false], null: true field :friends, [Types::CharacterType, null: false], null: false end end
  • 48. GraphQL Unions { search(in: "Adventure Time") { __typename ... on Character { firstName } ... on land { name } ... on Building { type } } } { "data": { "search": [ { "__typename": "Character", "firstName": "Finn" }, { "__typename": "Land", "name": "Land of Ooo" }, { "__typename": "Building", "type": "Fort" } ] } }
  • 49. GraphQL Unions union Result = Character | Land | Building type Character { firstName: String! } type Building { type: String! } type Land { name: String! } type Query { search: [Result] }
  • 50. GraphQL Unions union Result = Character | Land | Building type Character { firstName: String! } type Building { type: String! } type Land { name: String! } type Query { search: [Result] }
  • 51. GraphQL Unions class Types::ResultType < Types::BaseUnion possible_types Types::CharacterType, Types::LandType, Types::BuildingType # Optional: if this method is defined, it will override `Schema.resolve_type` def self.resolve_type(object, context) if object.is_a?(Character) Types::CharacterType elsif object.is_a?(Land) Types::LandType else Types::BuildingType end end end
  • 53. GraphQL Interfaces interface Node { id: ID! } interface Person { firstName: String! lastName: String } type Land implements Node { id: ID! name: String! } type Character implements Node & Person { id: ID! firstName: String! lastName: String }
  • 54. GraphQL Interfaces module Types::Interfaces::Node include Types::BaseInterface field :id, ID, null: false end module Types::Interfaces::Person include Types::BaseInterface field :first_name, String, null: false field :last_name, String, null: true end module Types class CharacterType < BaseObject implements Types::Interfaces::Node implements Types::Interfaces::Person end end
  • 56. GraphQL Fragments query { character { firstName lastName friends { firstName lastName } } }
  • 57. GraphQL Fragments fragment CharacterFragment on Character { firstName lastName } query { character { ...CharacterFragment friends { ...CharacterFragment } } }
  • 59. GraphQL Aliases query { hero: character(hero: true) { firstName } antihero: character(hero: false) { firstName } } { "data": { "hero": { "firstName": "Harrison", }, "antihero": { "firstName": "Sebastian", } } }
  • 61. GraphQL Directives • @deprecated(reason: String) - marks fields as deprecated with messages • @skip(if: Boolean!) - GraphQL execution skips the field if true by not calling the resolver • @include(id: Boolean!) - Calls resolver for annotated field if true GraphQL provides several built-in directives:
  • 62. GraphQL Directives query { character { firstName lastName friends @skip(if: $isAlone){ firstName lastName } } } type Character { firstName: String! lastName: String surname: String @deprecated(reason: "Use lastName. Will be removed...") friends: [Character!] }
  • 63. GraphQL Directives: Custom Directive class Directives::Rest < GraphQL::Schema::Directive description "..." locations( GraphQL::Schema::Directive::FIELD, GraphQL::Schema::Directive::FRAGMENT_SPREAD, GraphQL::Schema::Directive::INLINE_FRAGMENT ) argument :url, String, required: true, description: "..." def self.include?(obj, args, ctx) # implementation end def self.resolve(obj, args, ctx) # implementation end end
  • 64. query { character @rest(url: "/path") { firstName lastName friends { firstName lastName } } } GraphQL Directives: Custom Directive
  • 66. GraphQL Input Objects mutation CreateCharacter( $firstName: String! $lastName: String $role: RoleEnum! ) { createCharacter( firstName: $firstName lastName: $lastName role: $role ) { firstName lastName role } } mutation CreateCharacter( $input: CharacterAttributes! ) { createCharacter(input: $input) { firstName lastName role } }
  • 67. GraphQL Input Objects input CharacterAttributes { firstName: String! lastName: String role: RoleEnum! } class Types::CharacterAttributes < Types::BaseInputObject argument :first_name, String, required: true argument :last_name, String, required: false argument :role, Types::RoleEnum, required: false end
  • 70. GraphQL Schema schema { query: Query mutation: Mutation subscription: Subscription } class MySchema < GraphQL::Schema # Required: query Types::QueryType # Optional: mutation Types::MutationType subscription Types::SubscriptionType end
  • 71. GraphQL Schema class Types::QueryType < GraphQL::Schema::Object field :character, Types::CharacterType, resolver: Resolvers::Character end # Similarly: class Types::MutationType < GraphQL::Schema::Object # ... end # and class Types::SubscriptionType < GraphQL::Schema::Object # ... end type Query { character(id: ID!): CharacterType }
  • 72. What GraphQL SDL gives us?
  • 73. What GraphQL SDL gives us? Documentation
  • 74. What GraphQL SDL gives us? Documentation is the first class citizen in GraphQL
  • 75. GraphQL Execution How to do with GraphQL? 🚀
  • 76. When executing a GraphQL query one of the very first things the server needs to do is transform the query (currently a string) into something it understands. Transport
  • 77. Transport • HTTP POST • one endpoint (e.g. /graphql) • response code 200 OK
  • 79. GraphQL-Ruby Phases of Execution • Tokenize: splits the string into a stream of tokens • Parse: builds an abstract syntax tree (AST) out of the stream of tokens • Validate: validates the incoming AST as a valid query for the schema • Rewrite: builds a tree of nodes which express the query in a simpler way than the AST • Analyze: if there are any query analyzers, they are run • Execute: the query is traversed, resolve functions are called and the response is built • Respond: the response is returned as a Hash
  • 81. Tokenize & Parsing GraphQL has its own grammar. We need this rules to split up the query.  GraphQL Ruby uses a tool called Ragel to generate its lexer. How to understand that we have valid data?
  • 82. How to verify incoming data? • Breaks up a stream of characters (in our case a GraphQL query) into tokens • Turns sequences of tokens into a more abstract representation of the language
  • 83. Lexer query { character { firstName lastName friends { firstName lastName } } } GraphQL.scan(query) => [ (QUERY "query" [2:1]), (LCURLY "{" [2:7]), (IDENTIFIER "character" [3:3]), (LCURLY "{" [3:13]), (IDENTIFIER "firstName" [4:5]), (IDENTIFIER "lastName" [5:5]), (IDENTIFIER "friends" [6:5]), (LCURLY "{" [6:13]), (IDENTIFIER "firstName" [7:7]), (IDENTIFIER "lastName" [8:7]), (RCURLY "}" [9:5]), (RCURLY "}" [10:3]), (RCURLY "}" [11:1]) ]
  • 84. Parser query { character { firstName lastName friends { firstName lastName } } } GraphQL.parse(query) => #<GraphQL::Language::Nodes::Document:0x00007fbd8ae3dec0 @definitions= [#<GraphQL::Language::Nodes::OperationDefinition:… @col=1, @directives=[], @filename=nil, @line=2, @name=nil, @operation_type="query", @selections= [#<GraphQL::Language::Nodes::Field:… @alias=nil, @arguments=[], @col=3, @directives=[], @filename=nil, @line=3, @name="character"
  • 85. Lexer & Parser Javascript implementation of GraphQL has hand-written lexer and parser. GraphQL Ruby uses a tool called Ragel to generate its lexer. GraphQL Ruby uses a tool called Racc to generate its parser.
  • 86. GraphQL-Ruby Phases of Execution Tokenizing and Parsing are fundamental steps in the execution process. Validating, Rewriting, Analyzing, Executing are just details of the implementation.
  • 88. Pitfalls • Authentication • File uploading • N+1 • Caching • Performance
  • 89. Authentication • One endpoint • Handle guests and registered users • Fetch schema definition • Solutions: 1. auth processes with GraphQL 2. auth by tokens (JWT, OAuth) (check tokens)
  • 90. File uploading • Vanilla GraphQL doesn’t support throwing raw files into your mutations • Solutions: 1. Base64 Encoding 2. Separate Upload Requests 3. GraphQL Multipart Requests(most recommended)
  • 91. N+1 • The server executes multiple unnecessary round trips to data stores for nested data • Problem in how GraphQL works, not Ruby • Solutions: 1. preload data 2. gem ‘graphql-batch’ 3. gem ‘batch-loader’
  • 92. Caching • Transport-agnostic • Uses POST with HTTP • Don’t have url with identifier • Solution: 1. Server side caching(Memcache, Redis, etc.)
  • 93. Performance • Big queries can bring your server down to its knees • Solutions: 1. Set query timeout 2. Check query depth 3. Check query complexity
  • 94. Links • https://graphql.org • https://gql.foundation • https://graphql.github.io/graphql-spec • https://graphql-ruby.org • https://github.com/valikos/rm-27