SlideShare a Scribd company logo
How to grow GraphQL and
remove SQLAlchemy and REST
API from a high-load Python
project
Oleksandr Tarasenko
EVO.company / prom.ua
Some of prom.ua numbers
● RPS 2500-3500
● total sites over 300 000
● products ~ 150 million
● pages ~ 400 million
2
What we had
● monolithic WSGI app (11 years)
● mako templates
● monolithic database
● monolithic Nginx
● poor REST API for all sub-services
● slow Delivery and Deployment
● new features were hard to develop
3
4
GraphQL
http://graphql.org/users/
5
http://graphql.org/users/ 6
Key History Notes
● 2008 - Start. SQLAlchemy
● 2014 - SQLConstruct
● 2014 - ElasticSearch ecosystem
● 2016 - GraphQL
● 2017 - Microservices way
● 2018 - Python 3.7 + async
7
GraphQL concept in prom.ua
● new client-proposal paradigm
● good for read-only requests and data
● two-level (x-level) graph:
○ low-level graph for database mapping (data
loading)
○ high-level graph for business logic
● auto documentation and easy testing with
graphiql tool
● data validation 8
9
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via different Graph APIs
Step 4. Replace SQLAlchemy models logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
Why we choose GraphQL
● good for read-only requests and data
● no mutations needed
● hard to update REST API versions (v1, v2,...vn)
● auto generated documentation
● new client-proposal paradigm
● difficult routes
10
2016
● hiku, https://hiku.readthedocs.io/
● two-level graph
● mobile API with DSL-QL (EDN)
11
from hiku.graph import Graph, Node, Link, Field, ...
from hiku.sources import sqlalchemy as sa
from hiku.types import Boolean, Integer, String, TypeRef, ...
product_query = sa.FieldsQuery('db.session', Product.__table__)
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
Field('name', String, product_query),
Field('price', None, product_query),
...
])
12
from hiku.graph import Graph, Node, Link, Field
from hiku.sources import sqlalchemy as sa
from hiku.types import Boolean, Integer, String, TypeRef
product_query = sa.FieldsQuery('db.session', Product.__table__)
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
Field('name', String, product_query),
Field('price', None, product_query),
...
])
13
from hiku.graph import Graph, Node, Link, Field
from hiku.sources import sqlalchemy as sa
from hiku.types import Boolean, Integer, String, TypeRef
product_query = sa.FieldsQuery('db.session', Product.__table__)
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
Field('name', String, product_query),
Field('price', None, product_query),
...
])
14
15
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via different Graph APIs
Step 4. Replace SQLAlchemy models logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
2017
● hiku upgrade to native GraphQL
● new site 2nd level graph
● reimplementing mobile sites
● SSR Node.js Apollo Client
● success story with metrics
16
17
Frontend
18
Node.js
Node.js implementation
● Only for the first request (SSR)
● Good for React prerender
● Routing
● Two-step implementation
19
20
21
22
Success metrics
23
from 20.5% to 14.5%
Success metrics
24
from 57.5% to 49%
??? metrics
25
from 46 to 36
Some of the numbers of the new scheme
● node.js workers 3-6 per front
● React render 5 ms
● prom.ua workers over 750
● number of requests split to node/python
26
27
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via
different Graph APIs
Step 4. Replace SQLAlchemy models logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
Early 2018
● new order and shopping cart graphs
● new user cabinet
● Node.js and apollo for stitching two
graphs
● REST API under GraphQL
28
GraphQL schema stitching
29https://labs.getninjas.com.br/sharing-data-in-a-microservices-architecture-using-graphql-97db59357602
31
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via different Graph APIs
Step 4. Replace SQLAlchemy models
logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
Middle 2018
● Hiku upgrade to aliases and new data types
● Use SSR + GraphQL for portal mobile version
● Graph for replace SQLAlchemy models logic
and queries
● Rewriting sites SQL queries to GraphQL
● Remove Models from BL
● https://hiku.readthedocs.io/
32
product_query = sa.FieldsQuery('db.session', Product.__table__)
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
Field('name', String, product_query),
Field('price', None, product_query),
...
])
33
product_query = sa.FieldsQuery('db.session', Product.__table__)
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
Field('name', String, product_query),
Field('price', None, product_query),
...
])
34
product(ids: [1234, 1235]) {
id
name
price
}
"""
SELECT id, name, price FROM product
WHERE id IN (:id1, :id2, ..., :idN)
"""
35
product(ids: [1234, 1235]) {
id
name
price
}
"""
SELECT id, name, price FROM product
WHERE id IN (:id1, :id2, ..., :idN)
"""
36
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
...
Link(
'discount',
Optional[TypeRef['Discount']],
product_to_discount_query,
requires='id',
),
]),
Node('Discount', [
Field('id', Integer, discount_query),
Field('amount', Integer, discount_query),
])
])
37
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
...
Link(
'discount',
Optional[TypeRef['Discount']],
product_to_discount_query,
requires='id',
),
]),
Node('Discount', [
Field('id', Integer, discount_query),
Field('amount', Integer, discount_query),
])
])
38
low_level_graph = Graph([
Node('Product', [
Field('id', Integer, product_query),
...
Link(
'discount',
Optional[TypeRef['Discount']],
product_to_discount_query,
requires='id',
),
]),
Node('Discount', [
Field('id', Integer, discount_query),
Field('amount', Integer, discount_query),
])
])
39
40
discount_query = sa.FieldsQuery('db.session', Discount.__table__)
"""
SELECT id, name, price, price_currency_id FROM product
WHERE id IN (:id1, :id2, ..., :idN)
"""
product_to_discount_query = sa.LinkQuery(
'db.session',
from_column=Discount.product_id,
to_column=Discount.product_id,
)
"""
SELECT product_id FROM discount
WHERE product_id IN (:id1, :id2, ..., :idN)
"""
41
discount_query = sa.FieldsQuery('db.session', Discount.__table__)
"""
SELECT id, name, price, price_currency_id FROM product
WHERE id IN (:id1, :id2, ..., :idN)
"""
product_to_discount_query = sa.LinkQuery(
'db.session',
from_column=Discount.product_id,
to_column=Discount.product_id,
)
"""
SELECT product_id FROM discount
WHERE product_id IN (:id1, :id2, ..., :idN)
"""
42
product_sg = SubGraph(low_level_graph, 'Product')
high_level_graph = Graph([
Node('Product', [
Field('id', String, product_sg),
Field('name', String, product_sg.compile(S.this.name)),
Field('priceText', String, product_sg.compile(
get_price_text(S.this)
)),
Field('hasDiscount', Boolean, product_sg.compile(
is_discount_available(S.this, S.this.discount)
)),
Field('discountedPriceText', String, product_sg.compile(
get_discounted_price_text(S.this, S.this.discount)
)),
]),
])
43
product_sg = SubGraph(low_level_graph, 'Product')
high_level_graph = Graph([
Node('Product', [
Field('id', String, product_sg),
Field('name', String, product_sg.compile(S.this.name)),
Field('priceText', String, product_sg.compile(
get_price_text(S.this)
)),
Field('hasDiscount', Boolean, product_sg.compile(
is_discount_available(S.this, S.this.discount)
)),
Field('discountedPriceText', String, product_sg.compile(
get_discounted_price_text(S.this, S.this.discount)
)),
]),
])
44
product_sg = SubGraph(low_level_graph, 'Product')
high_level_graph = Graph([
Node('Product', [
Field('id', String, product_sg),
Field('name', String, product_sg.compile(S.this.name)),
Field('priceText', String, product_sg.compile(
get_price_text(S.this)
)),
Field('hasDiscount', Boolean, product_sg.compile(
is_discount_available(S.this, S.this.discount)
)),
Field('discountedPriceText', String, product_sg.compile(
get_discounted_price_text(S.this, S.this.discount)
)),
]),
])
45
@define(Record[{
'price': Float,
'price_currency_id': Integer,
'currency_settings': Any
}])
def get_price_text(product):
product_price_text = format_currency_data(
product_price,
product['price_currency_id'],
)
...
//..
return product_price_text.formatted_number
Key History Notes
● 2008 - Start. SqlAlchemy
● 2014 - SQL Construct
● 2014 - ElasticSearch ecosystem
● 2016 - GraphQL
● 2017 - Microservices way
● 2018 - Python 3.7 + async
46
47
Python 3.7 + Async + GraphQL
48
def link_to_some_product(opts):
product = db.session.query(
Product.id
).filter(
Product.id == opts['id'],
Product.status_on_display(),
).first()
if product is not None:
return product.id
else:
return Nothing
49
async def link_to_some_product(opts):
expr = select([Product.id]).where(
and_(
Product.id == opts['id'],
Product.status_on_display()
)
)
async with async_engine() as query_ctx:
product_id = await query_ctx.scalar(expr)
return product_id or Nothing
50
async def link_to_some_product(opts):
expr = select([Product.id]).where(
and_(
Product.id == opts['id'],
Product.status_on_display()
)
)
async with async_engine() as query_ctx:
product_id = await query_ctx.scalar(expr)
return product_id or Nothing
51
product_query = sa.FieldsQuery(
'db.session', Product.__table__)
product_query = asyncsa.FieldsQuery(
'db.session_async', Product.table)
52
product_query = sa.FieldsQuery(
'db.session', Product.__table__)
product_query = asyncsa.FieldsQuery(
'db.session_async', Product.__table__)
Mobile API average across all queries:
383 ms -> 323 ms 15%
Catalog Graph API average across all queries:
82 ms -> 62 ms 25%
Site Graph Api average across all queries
121 ms -> 108 ms 11%
Async + GraphQL results
54
Example with aliases
def get_price_lists_data():
query = build([
Q.priceLists[
Q.id,
Q.name,
Q.file_id << Q.priceFileId,
Q.date_posted << Q.datePosted,
Q.url << Q.fileUrl,
]
])
graph_data = execute(query)
return graph_data.priceLists
55
Example with aliases
def get_price_lists_data():
query = build([
Q.priceLists[
Q.id,
Q.name,
Q.file_id << Q.priceFileId,
Q.date_posted << Q.datePosted,
Q.url << Q.fileUrl,
]
])
graph_data = execute(query)
return graph_data.priceLists
A few facts of prom.ua graphs
● number of graphs: ~ 20
● number of fields: ~ 2000
● number of links: ~ 300
● number of nodes: ~ 250
● single entry point /graphql
● refactoring and new vision for code
● better monitoring
● easy to test API with graphiql
56
Hiku
57
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via different Graph APIs
Step 4. Replace SQLAlchemy models logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
End of 2018 - now
● Hiku upgrade to mutations
● New 2nd level graph for opinions and
mobile cabinet API
● Read and write with graph
58
mutation_graph = Graph(repr_graph.nodes + [
Root([
Link(
'addNewOpinion',
TypeRef['NewCommentResult'],
add_new_comment_for_opinion,
options=[
Option('opinion_id', Integer),
Option('comment', String),
], requires=None,
),
]),
])
mutation_graph = Graph(repr_graph.nodes + [
Root([
Link(
'addNewOpinion',
TypeRef['NewCommentResult'],
add_new_comment_for_opinion,
options=[
Option('opinion_id', Integer),
Option('comment', String),
], requires=None,
),
]),
])
def add_new_comment_for_opinion(ctx, options):
opinion_id = options['opinion_id']
comment = options['comment']
user = ctx['user']
opinion = Opinion.get(opinion_id)
...
form = OpinionCommentForm()
if not form.validate():
return NewCommentResult(id=None, errors=form.validate_resp())
comment = opinion.new_comment(...)
comment.message = clear_text(form.data['comment'])
comment.author_user_id = user.id
db.session.commit()
return NewCommentResult(id=comment.id, errors=[])
def add_new_comment_for_opinion(ctx, options):
opinion_id = options['opinion_id']
comment = options['comment']
user = ctx['user']
opinion = Opinion.get(opinion_id)
...
form = OpinionCommentForm()
if not form.validate():
return NewCommentResult(id=None, errors=form.validate_resp())
comment = opinion.new_comment(...)
comment.message = clear_text(form.data['comment'])
comment.author_user_id = user.id
db.session.commit()
return NewCommentResult(id=comment.id, errors=[])
def add_new_comment_for_opinion(ctx, options):
opinion_id = options['opinion_id']
comment = options['comment']
user = ctx['user']
opinion = Opinion.get(opinion_id)
...
form = OpinionCommentForm()
if not form.validate():
return NewCommentResult(id=None, errors=form.validate_resp())
comment = opinion.new_comment(...)
comment.message = clear_text(form.data['comment'])
comment.author_user_id = user.id
db.session.commit()
return NewCommentResult(id=comment.id, errors=[])
def add_new_comment_for_opinion(ctx, options):
opinion_id = options['opinion_id']
comment = options['comment']
user = ctx['user']
opinion = Opinion.get(opinion_id)
...
form = OpinionCommentForm()
if not form.validate():
return NewCommentResult(id=None, errors=form.validate_resp())
comment = opinion.new_comment(...)
comment.message = clear_text(form.data['comment'])
comment.author_user_id = user.id
db.session.commit()
return NewCommentResult(id=comment.id, errors=[])
65
Step 1. Mobile App API with GraphQL
Step 2. Separating Frontend from Backend
Step 3. Graph services as Proxy via different Graph APIs
Step 4. Replace SQLAlchemy models logic via Graph
Step 5. Mutations in Graph API
Step 6. A brave new world with GraphQL
New client-proposal paradigm
via GraphQL
GraphQL everywhere
Testing with hypothesis
Q/A
Hiku

More Related Content

What's hot

Building interactive web app with shiny
Building interactive web app with shinyBuilding interactive web app with shiny
Building interactive web app with shiny
Vivian S. Zhang
 
Recoil at Codete Webinars #3
Recoil at Codete Webinars #3Recoil at Codete Webinars #3
Recoil at Codete Webinars #3
Mateusz Bryła
 
Building a GraphQL API in PHP
Building a GraphQL API in PHPBuilding a GraphQL API in PHP
Building a GraphQL API in PHP
Andrew Rota
 
Smarter data analysis with JavaScript and Azure ML functions in Excel
Smarter data analysis with JavaScript and Azure ML functions in ExcelSmarter data analysis with JavaScript and Azure ML functions in Excel
Smarter data analysis with JavaScript and Azure ML functions in Excel
Microsoft Tech Community
 
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Performant APIs with GraphQL and PHP (Dutch PHP 2019)Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Andrew Rota
 
Charting with Google
Charting with GoogleCharting with Google
Charting with Google
Russell Heimlich
 
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
Kanika Garg
 
Integrating React.js Into a PHP Application: Dutch PHP 2019
Integrating React.js Into a PHP Application: Dutch PHP 2019Integrating React.js Into a PHP Application: Dutch PHP 2019
Integrating React.js Into a PHP Application: Dutch PHP 2019
Andrew Rota
 

What's hot (8)

Building interactive web app with shiny
Building interactive web app with shinyBuilding interactive web app with shiny
Building interactive web app with shiny
 
Recoil at Codete Webinars #3
Recoil at Codete Webinars #3Recoil at Codete Webinars #3
Recoil at Codete Webinars #3
 
Building a GraphQL API in PHP
Building a GraphQL API in PHPBuilding a GraphQL API in PHP
Building a GraphQL API in PHP
 
Smarter data analysis with JavaScript and Azure ML functions in Excel
Smarter data analysis with JavaScript and Azure ML functions in ExcelSmarter data analysis with JavaScript and Azure ML functions in Excel
Smarter data analysis with JavaScript and Azure ML functions in Excel
 
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Performant APIs with GraphQL and PHP (Dutch PHP 2019)Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
 
Charting with Google
Charting with GoogleCharting with Google
Charting with Google
 
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
Google Chart Tools Kanika Garg (10BM60035) Lavanya R. (10BM60042)
 
Integrating React.js Into a PHP Application: Dutch PHP 2019
Integrating React.js Into a PHP Application: Dutch PHP 2019Integrating React.js Into a PHP Application: Dutch PHP 2019
Integrating React.js Into a PHP Application: Dutch PHP 2019
 

Similar to How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Python project - Pycon Belarus 2019

How to separate frontend from a highload python project with no problems - Py...
How to separate frontend from a highload python project with no problems - Py...How to separate frontend from a highload python project with no problems - Py...
How to separate frontend from a highload python project with no problems - Py...
Oleksandr Tarasenko
 
Oleksandr Tarasenko "ORM vs GraphQL"
Oleksandr Tarasenko "ORM vs GraphQL"Oleksandr Tarasenko "ORM vs GraphQL"
Oleksandr Tarasenko "ORM vs GraphQL"
Fwdays
 
ORM vs GraphQL - Python fwdays 2019
ORM vs GraphQL - Python fwdays 2019ORM vs GraphQL - Python fwdays 2019
ORM vs GraphQL - Python fwdays 2019
Oleksandr Tarasenko
 
GraphQL the holy contract between client and server
GraphQL the holy contract between client and serverGraphQL the holy contract between client and server
GraphQL the holy contract between client and server
Pavel Chertorogov
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from Scratch
Nikolas Burk
 
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
Noriaki Tatsumi
 
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) ExtensionSimplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
VMware Tanzu
 
Nikita Galkin "Looking for the right tech stack for GraphQL application"
Nikita Galkin "Looking for the right tech stack for GraphQL application"Nikita Galkin "Looking for the right tech stack for GraphQL application"
Nikita Galkin "Looking for the right tech stack for GraphQL application"
Fwdays
 
Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)
Python Ireland
 
Elixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.jsElixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.js
Jeroen Visser
 
Multiple Graphs: Updatable Views
Multiple Graphs: Updatable ViewsMultiple Graphs: Updatable Views
Multiple Graphs: Updatable Views
openCypher
 
Automotive industry ppt
Automotive industry pptAutomotive industry ppt
Automotive industry ppt
sudharsanpremkumar1
 
Managing GraphQL servers with AWS Fargate & Prisma Cloud
Managing GraphQL servers  with AWS Fargate & Prisma CloudManaging GraphQL servers  with AWS Fargate & Prisma Cloud
Managing GraphQL servers with AWS Fargate & Prisma Cloud
Nikolas Burk
 
Serverless GraphQL with AWS AppSync & AWS Amplify
Serverless GraphQL with AWS AppSync & AWS AmplifyServerless GraphQL with AWS AppSync & AWS Amplify
Serverless GraphQL with AWS AppSync & AWS Amplify
Kentucky JavaScript Users Group
 
Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...
Paweł Żurowski
 
Bringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production readyBringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production ready
yann_s
 
VMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with ClarityVMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with Clarity
Jeeyun Lim
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
Tobias Meixner
 
GraphQL & DGraph with Go
GraphQL & DGraph with GoGraphQL & DGraph with Go
GraphQL & DGraph with Go
James Tan
 

Similar to How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Python project - Pycon Belarus 2019 (20)

How to separate frontend from a highload python project with no problems - Py...
How to separate frontend from a highload python project with no problems - Py...How to separate frontend from a highload python project with no problems - Py...
How to separate frontend from a highload python project with no problems - Py...
 
Oleksandr Tarasenko "ORM vs GraphQL"
Oleksandr Tarasenko "ORM vs GraphQL"Oleksandr Tarasenko "ORM vs GraphQL"
Oleksandr Tarasenko "ORM vs GraphQL"
 
ORM vs GraphQL - Python fwdays 2019
ORM vs GraphQL - Python fwdays 2019ORM vs GraphQL - Python fwdays 2019
ORM vs GraphQL - Python fwdays 2019
 
GraphQL the holy contract between client and server
GraphQL the holy contract between client and serverGraphQL the holy contract between client and server
GraphQL the holy contract between client and server
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from Scratch
 
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
GraphQL Summit 2019 - Configuration Driven Data as a Service Gateway with Gra...
 
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) ExtensionSimplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
 
Nikita Galkin "Looking for the right tech stack for GraphQL application"
Nikita Galkin "Looking for the right tech stack for GraphQL application"Nikita Galkin "Looking for the right tech stack for GraphQL application"
Nikita Galkin "Looking for the right tech stack for GraphQL application"
 
Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)
 
Elixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.jsElixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.js
 
Multiple Graphs: Updatable Views
Multiple Graphs: Updatable ViewsMultiple Graphs: Updatable Views
Multiple Graphs: Updatable Views
 
Automotive industry ppt
Automotive industry pptAutomotive industry ppt
Automotive industry ppt
 
Managing GraphQL servers with AWS Fargate & Prisma Cloud
Managing GraphQL servers  with AWS Fargate & Prisma CloudManaging GraphQL servers  with AWS Fargate & Prisma Cloud
Managing GraphQL servers with AWS Fargate & Prisma Cloud
 
Serverless GraphQL with AWS AppSync & AWS Amplify
Serverless GraphQL with AWS AppSync & AWS AmplifyServerless GraphQL with AWS AppSync & AWS Amplify
Serverless GraphQL with AWS AppSync & AWS Amplify
 
Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...
 
Bringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production readyBringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production ready
 
VMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with ClarityVMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with Clarity
 
ql.io at NodePDX
ql.io at NodePDXql.io at NodePDX
ql.io at NodePDX
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
 
GraphQL & DGraph with Go
GraphQL & DGraph with GoGraphQL & DGraph with Go
GraphQL & DGraph with Go
 

Recently uploaded

The role of big data in decision making.
The role of big data in decision making.The role of big data in decision making.
The role of big data in decision making.
ankuprajapati0525
 
Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.
PrashantGoswami42
 
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptxCFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
R&R Consult
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
Pipe Restoration Solutions
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
JoytuBarua2
 
Courier management system project report.pdf
Courier management system project report.pdfCourier management system project report.pdf
Courier management system project report.pdf
Kamal Acharya
 
LIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.pptLIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.ppt
ssuser9bd3ba
 
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdfTop 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
Teleport Manpower Consultant
 
Final project report on grocery store management system..pdf
Final project report on grocery store management system..pdfFinal project report on grocery store management system..pdf
Final project report on grocery store management system..pdf
Kamal Acharya
 
TECHNICAL TRAINING MANUAL GENERAL FAMILIARIZATION COURSE
TECHNICAL TRAINING MANUAL   GENERAL FAMILIARIZATION COURSETECHNICAL TRAINING MANUAL   GENERAL FAMILIARIZATION COURSE
TECHNICAL TRAINING MANUAL GENERAL FAMILIARIZATION COURSE
DuvanRamosGarzon1
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
FluxPrime1
 
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
bakpo1
 
Democratizing Fuzzing at Scale by Abhishek Arya
Democratizing Fuzzing at Scale by Abhishek AryaDemocratizing Fuzzing at Scale by Abhishek Arya
Democratizing Fuzzing at Scale by Abhishek Arya
abh.arya
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
seandesed
 
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdfCOLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
Kamal Acharya
 
H.Seo, ICLR 2024, MLILAB, KAIST AI.pdf
H.Seo,  ICLR 2024, MLILAB,  KAIST AI.pdfH.Seo,  ICLR 2024, MLILAB,  KAIST AI.pdf
H.Seo, ICLR 2024, MLILAB, KAIST AI.pdf
MLILAB
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
Intella Parts
 
CME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional ElectiveCME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional Elective
karthi keyan
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
Kamal Acharya
 
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdfAKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
SamSarthak3
 

Recently uploaded (20)

The role of big data in decision making.
The role of big data in decision making.The role of big data in decision making.
The role of big data in decision making.
 
Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.
 
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptxCFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
CFD Simulation of By-pass Flow in a HRSG module by R&R Consult.pptx
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
 
Courier management system project report.pdf
Courier management system project report.pdfCourier management system project report.pdf
Courier management system project report.pdf
 
LIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.pptLIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.ppt
 
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdfTop 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
Top 10 Oil and Gas Projects in Saudi Arabia 2024.pdf
 
Final project report on grocery store management system..pdf
Final project report on grocery store management system..pdfFinal project report on grocery store management system..pdf
Final project report on grocery store management system..pdf
 
TECHNICAL TRAINING MANUAL GENERAL FAMILIARIZATION COURSE
TECHNICAL TRAINING MANUAL   GENERAL FAMILIARIZATION COURSETECHNICAL TRAINING MANUAL   GENERAL FAMILIARIZATION COURSE
TECHNICAL TRAINING MANUAL GENERAL FAMILIARIZATION COURSE
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
 
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
 
Democratizing Fuzzing at Scale by Abhishek Arya
Democratizing Fuzzing at Scale by Abhishek AryaDemocratizing Fuzzing at Scale by Abhishek Arya
Democratizing Fuzzing at Scale by Abhishek Arya
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
 
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdfCOLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
 
H.Seo, ICLR 2024, MLILAB, KAIST AI.pdf
H.Seo,  ICLR 2024, MLILAB,  KAIST AI.pdfH.Seo,  ICLR 2024, MLILAB,  KAIST AI.pdf
H.Seo, ICLR 2024, MLILAB, KAIST AI.pdf
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
 
CME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional ElectiveCME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional Elective
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
 
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdfAKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
AKS UNIVERSITY Satna Final Year Project By OM Hardaha.pdf
 

How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Python project - Pycon Belarus 2019

  • 1. How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Python project Oleksandr Tarasenko EVO.company / prom.ua
  • 2. Some of prom.ua numbers ● RPS 2500-3500 ● total sites over 300 000 ● products ~ 150 million ● pages ~ 400 million 2
  • 3. What we had ● monolithic WSGI app (11 years) ● mako templates ● monolithic database ● monolithic Nginx ● poor REST API for all sub-services ● slow Delivery and Deployment ● new features were hard to develop 3
  • 7. Key History Notes ● 2008 - Start. SQLAlchemy ● 2014 - SQLConstruct ● 2014 - ElasticSearch ecosystem ● 2016 - GraphQL ● 2017 - Microservices way ● 2018 - Python 3.7 + async 7
  • 8. GraphQL concept in prom.ua ● new client-proposal paradigm ● good for read-only requests and data ● two-level (x-level) graph: ○ low-level graph for database mapping (data loading) ○ high-level graph for business logic ● auto documentation and easy testing with graphiql tool ● data validation 8
  • 9. 9 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL
  • 10. Why we choose GraphQL ● good for read-only requests and data ● no mutations needed ● hard to update REST API versions (v1, v2,...vn) ● auto generated documentation ● new client-proposal paradigm ● difficult routes 10
  • 11. 2016 ● hiku, https://hiku.readthedocs.io/ ● two-level graph ● mobile API with DSL-QL (EDN) 11
  • 12. from hiku.graph import Graph, Node, Link, Field, ... from hiku.sources import sqlalchemy as sa from hiku.types import Boolean, Integer, String, TypeRef, ... product_query = sa.FieldsQuery('db.session', Product.__table__) low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), Field('name', String, product_query), Field('price', None, product_query), ... ]) 12
  • 13. from hiku.graph import Graph, Node, Link, Field from hiku.sources import sqlalchemy as sa from hiku.types import Boolean, Integer, String, TypeRef product_query = sa.FieldsQuery('db.session', Product.__table__) low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), Field('name', String, product_query), Field('price', None, product_query), ... ]) 13
  • 14. from hiku.graph import Graph, Node, Link, Field from hiku.sources import sqlalchemy as sa from hiku.types import Boolean, Integer, String, TypeRef product_query = sa.FieldsQuery('db.session', Product.__table__) low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), Field('name', String, product_query), Field('price', None, product_query), ... ]) 14
  • 15. 15 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL
  • 16. 2017 ● hiku upgrade to native GraphQL ● new site 2nd level graph ● reimplementing mobile sites ● SSR Node.js Apollo Client ● success story with metrics 16
  • 19. Node.js implementation ● Only for the first request (SSR) ● Good for React prerender ● Routing ● Two-step implementation 19
  • 20. 20
  • 21. 21
  • 22. 22
  • 26. Some of the numbers of the new scheme ● node.js workers 3-6 per front ● React render 5 ms ● prom.ua workers over 750 ● number of requests split to node/python 26
  • 27. 27 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL
  • 28. Early 2018 ● new order and shopping cart graphs ● new user cabinet ● Node.js and apollo for stitching two graphs ● REST API under GraphQL 28
  • 30.
  • 31. 31 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL
  • 32. Middle 2018 ● Hiku upgrade to aliases and new data types ● Use SSR + GraphQL for portal mobile version ● Graph for replace SQLAlchemy models logic and queries ● Rewriting sites SQL queries to GraphQL ● Remove Models from BL ● https://hiku.readthedocs.io/ 32
  • 33. product_query = sa.FieldsQuery('db.session', Product.__table__) low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), Field('name', String, product_query), Field('price', None, product_query), ... ]) 33
  • 34. product_query = sa.FieldsQuery('db.session', Product.__table__) low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), Field('name', String, product_query), Field('price', None, product_query), ... ]) 34
  • 35. product(ids: [1234, 1235]) { id name price } """ SELECT id, name, price FROM product WHERE id IN (:id1, :id2, ..., :idN) """ 35
  • 36. product(ids: [1234, 1235]) { id name price } """ SELECT id, name, price FROM product WHERE id IN (:id1, :id2, ..., :idN) """ 36
  • 37. low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), ... Link( 'discount', Optional[TypeRef['Discount']], product_to_discount_query, requires='id', ), ]), Node('Discount', [ Field('id', Integer, discount_query), Field('amount', Integer, discount_query), ]) ]) 37
  • 38. low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), ... Link( 'discount', Optional[TypeRef['Discount']], product_to_discount_query, requires='id', ), ]), Node('Discount', [ Field('id', Integer, discount_query), Field('amount', Integer, discount_query), ]) ]) 38
  • 39. low_level_graph = Graph([ Node('Product', [ Field('id', Integer, product_query), ... Link( 'discount', Optional[TypeRef['Discount']], product_to_discount_query, requires='id', ), ]), Node('Discount', [ Field('id', Integer, discount_query), Field('amount', Integer, discount_query), ]) ]) 39
  • 40. 40 discount_query = sa.FieldsQuery('db.session', Discount.__table__) """ SELECT id, name, price, price_currency_id FROM product WHERE id IN (:id1, :id2, ..., :idN) """ product_to_discount_query = sa.LinkQuery( 'db.session', from_column=Discount.product_id, to_column=Discount.product_id, ) """ SELECT product_id FROM discount WHERE product_id IN (:id1, :id2, ..., :idN) """
  • 41. 41 discount_query = sa.FieldsQuery('db.session', Discount.__table__) """ SELECT id, name, price, price_currency_id FROM product WHERE id IN (:id1, :id2, ..., :idN) """ product_to_discount_query = sa.LinkQuery( 'db.session', from_column=Discount.product_id, to_column=Discount.product_id, ) """ SELECT product_id FROM discount WHERE product_id IN (:id1, :id2, ..., :idN) """
  • 42. 42 product_sg = SubGraph(low_level_graph, 'Product') high_level_graph = Graph([ Node('Product', [ Field('id', String, product_sg), Field('name', String, product_sg.compile(S.this.name)), Field('priceText', String, product_sg.compile( get_price_text(S.this) )), Field('hasDiscount', Boolean, product_sg.compile( is_discount_available(S.this, S.this.discount) )), Field('discountedPriceText', String, product_sg.compile( get_discounted_price_text(S.this, S.this.discount) )), ]), ])
  • 43. 43 product_sg = SubGraph(low_level_graph, 'Product') high_level_graph = Graph([ Node('Product', [ Field('id', String, product_sg), Field('name', String, product_sg.compile(S.this.name)), Field('priceText', String, product_sg.compile( get_price_text(S.this) )), Field('hasDiscount', Boolean, product_sg.compile( is_discount_available(S.this, S.this.discount) )), Field('discountedPriceText', String, product_sg.compile( get_discounted_price_text(S.this, S.this.discount) )), ]), ])
  • 44. 44 product_sg = SubGraph(low_level_graph, 'Product') high_level_graph = Graph([ Node('Product', [ Field('id', String, product_sg), Field('name', String, product_sg.compile(S.this.name)), Field('priceText', String, product_sg.compile( get_price_text(S.this) )), Field('hasDiscount', Boolean, product_sg.compile( is_discount_available(S.this, S.this.discount) )), Field('discountedPriceText', String, product_sg.compile( get_discounted_price_text(S.this, S.this.discount) )), ]), ])
  • 45. 45 @define(Record[{ 'price': Float, 'price_currency_id': Integer, 'currency_settings': Any }]) def get_price_text(product): product_price_text = format_currency_data( product_price, product['price_currency_id'], ) ... //.. return product_price_text.formatted_number
  • 46. Key History Notes ● 2008 - Start. SqlAlchemy ● 2014 - SQL Construct ● 2014 - ElasticSearch ecosystem ● 2016 - GraphQL ● 2017 - Microservices way ● 2018 - Python 3.7 + async 46
  • 47. 47 Python 3.7 + Async + GraphQL
  • 48. 48 def link_to_some_product(opts): product = db.session.query( Product.id ).filter( Product.id == opts['id'], Product.status_on_display(), ).first() if product is not None: return product.id else: return Nothing
  • 49. 49 async def link_to_some_product(opts): expr = select([Product.id]).where( and_( Product.id == opts['id'], Product.status_on_display() ) ) async with async_engine() as query_ctx: product_id = await query_ctx.scalar(expr) return product_id or Nothing
  • 50. 50 async def link_to_some_product(opts): expr = select([Product.id]).where( and_( Product.id == opts['id'], Product.status_on_display() ) ) async with async_engine() as query_ctx: product_id = await query_ctx.scalar(expr) return product_id or Nothing
  • 51. 51 product_query = sa.FieldsQuery( 'db.session', Product.__table__) product_query = asyncsa.FieldsQuery( 'db.session_async', Product.table)
  • 52. 52 product_query = sa.FieldsQuery( 'db.session', Product.__table__) product_query = asyncsa.FieldsQuery( 'db.session_async', Product.__table__)
  • 53. Mobile API average across all queries: 383 ms -> 323 ms 15% Catalog Graph API average across all queries: 82 ms -> 62 ms 25% Site Graph Api average across all queries 121 ms -> 108 ms 11% Async + GraphQL results
  • 54. 54 Example with aliases def get_price_lists_data(): query = build([ Q.priceLists[ Q.id, Q.name, Q.file_id << Q.priceFileId, Q.date_posted << Q.datePosted, Q.url << Q.fileUrl, ] ]) graph_data = execute(query) return graph_data.priceLists
  • 55. 55 Example with aliases def get_price_lists_data(): query = build([ Q.priceLists[ Q.id, Q.name, Q.file_id << Q.priceFileId, Q.date_posted << Q.datePosted, Q.url << Q.fileUrl, ] ]) graph_data = execute(query) return graph_data.priceLists
  • 56. A few facts of prom.ua graphs ● number of graphs: ~ 20 ● number of fields: ~ 2000 ● number of links: ~ 300 ● number of nodes: ~ 250 ● single entry point /graphql ● refactoring and new vision for code ● better monitoring ● easy to test API with graphiql 56 Hiku
  • 57. 57 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL
  • 58. End of 2018 - now ● Hiku upgrade to mutations ● New 2nd level graph for opinions and mobile cabinet API ● Read and write with graph 58
  • 59. mutation_graph = Graph(repr_graph.nodes + [ Root([ Link( 'addNewOpinion', TypeRef['NewCommentResult'], add_new_comment_for_opinion, options=[ Option('opinion_id', Integer), Option('comment', String), ], requires=None, ), ]), ])
  • 60. mutation_graph = Graph(repr_graph.nodes + [ Root([ Link( 'addNewOpinion', TypeRef['NewCommentResult'], add_new_comment_for_opinion, options=[ Option('opinion_id', Integer), Option('comment', String), ], requires=None, ), ]), ])
  • 61. def add_new_comment_for_opinion(ctx, options): opinion_id = options['opinion_id'] comment = options['comment'] user = ctx['user'] opinion = Opinion.get(opinion_id) ... form = OpinionCommentForm() if not form.validate(): return NewCommentResult(id=None, errors=form.validate_resp()) comment = opinion.new_comment(...) comment.message = clear_text(form.data['comment']) comment.author_user_id = user.id db.session.commit() return NewCommentResult(id=comment.id, errors=[])
  • 62. def add_new_comment_for_opinion(ctx, options): opinion_id = options['opinion_id'] comment = options['comment'] user = ctx['user'] opinion = Opinion.get(opinion_id) ... form = OpinionCommentForm() if not form.validate(): return NewCommentResult(id=None, errors=form.validate_resp()) comment = opinion.new_comment(...) comment.message = clear_text(form.data['comment']) comment.author_user_id = user.id db.session.commit() return NewCommentResult(id=comment.id, errors=[])
  • 63. def add_new_comment_for_opinion(ctx, options): opinion_id = options['opinion_id'] comment = options['comment'] user = ctx['user'] opinion = Opinion.get(opinion_id) ... form = OpinionCommentForm() if not form.validate(): return NewCommentResult(id=None, errors=form.validate_resp()) comment = opinion.new_comment(...) comment.message = clear_text(form.data['comment']) comment.author_user_id = user.id db.session.commit() return NewCommentResult(id=comment.id, errors=[])
  • 64. def add_new_comment_for_opinion(ctx, options): opinion_id = options['opinion_id'] comment = options['comment'] user = ctx['user'] opinion = Opinion.get(opinion_id) ... form = OpinionCommentForm() if not form.validate(): return NewCommentResult(id=None, errors=form.validate_resp()) comment = opinion.new_comment(...) comment.message = clear_text(form.data['comment']) comment.author_user_id = user.id db.session.commit() return NewCommentResult(id=comment.id, errors=[])
  • 65. 65 Step 1. Mobile App API with GraphQL Step 2. Separating Frontend from Backend Step 3. Graph services as Proxy via different Graph APIs Step 4. Replace SQLAlchemy models logic via Graph Step 5. Mutations in Graph API Step 6. A brave new world with GraphQL