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
How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Python project - Pycon Belarus 2019
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
Ad

More Related Content

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
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
 
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
 
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
 

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
 
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
 
ql.io at NodePDX
ql.io at NodePDXql.io at NodePDX
ql.io at NodePDX
Subbu Allamaraju
 
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
 
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
 
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
 
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
 
Ad

Recently uploaded (20)

lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIHlecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
Abodahab
 
Data Structures_Linear data structures Linked Lists.pptx
Data Structures_Linear data structures Linked Lists.pptxData Structures_Linear data structures Linked Lists.pptx
Data Structures_Linear data structures Linked Lists.pptx
RushaliDeshmukh2
 
Artificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptxArtificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptx
aditichinar
 
Compiler Design_Lexical Analysis phase.pptx
Compiler Design_Lexical Analysis phase.pptxCompiler Design_Lexical Analysis phase.pptx
Compiler Design_Lexical Analysis phase.pptx
RushaliDeshmukh2
 
DSP and MV the Color image processing.ppt
DSP and MV the  Color image processing.pptDSP and MV the  Color image processing.ppt
DSP and MV the Color image processing.ppt
HafizAhamed8
 
Artificial Intelligence introduction.pptx
Artificial Intelligence introduction.pptxArtificial Intelligence introduction.pptx
Artificial Intelligence introduction.pptx
DrMarwaElsherif
 
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Journal of Soft Computing in Civil Engineering
 
theory-slides-for react for beginners.pptx
theory-slides-for react for beginners.pptxtheory-slides-for react for beginners.pptx
theory-slides-for react for beginners.pptx
sanchezvanessa7896
 
Development of MLR, ANN and ANFIS Models for Estimation of PCUs at Different ...
Development of MLR, ANN and ANFIS Models for Estimation of PCUs at Different ...Development of MLR, ANN and ANFIS Models for Estimation of PCUs at Different ...
Development of MLR, ANN and ANFIS Models for Estimation of PCUs at Different ...
Journal of Soft Computing in Civil Engineering
 
new ppt artificial intelligence historyyy
new ppt artificial intelligence historyyynew ppt artificial intelligence historyyy
new ppt artificial intelligence historyyy
PianoPianist
 
15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...
IJCSES Journal
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
charlesdick1345
 
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptxLidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
RishavKumar530754
 
New Microsoft PowerPoint Presentation.pdf
New Microsoft PowerPoint Presentation.pdfNew Microsoft PowerPoint Presentation.pdf
New Microsoft PowerPoint Presentation.pdf
mohamedezzat18803
 
Introduction to FLUID MECHANICS & KINEMATICS
Introduction to FLUID MECHANICS &  KINEMATICSIntroduction to FLUID MECHANICS &  KINEMATICS
Introduction to FLUID MECHANICS & KINEMATICS
narayanaswamygdas
 
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
inmishra17121973
 
Data Structures_Introduction to algorithms.pptx
Data Structures_Introduction to algorithms.pptxData Structures_Introduction to algorithms.pptx
Data Structures_Introduction to algorithms.pptx
RushaliDeshmukh2
 
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E..."Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
Infopitaara
 
Metal alkyne complexes.pptx in chemistry
Metal alkyne complexes.pptx in chemistryMetal alkyne complexes.pptx in chemistry
Metal alkyne complexes.pptx in chemistry
mee23nu
 
lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIHlecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
lecture5.pptxJHKGJFHDGTFGYIUOIUIPIOIPUOHIYGUYFGIH
Abodahab
 
Data Structures_Linear data structures Linked Lists.pptx
Data Structures_Linear data structures Linked Lists.pptxData Structures_Linear data structures Linked Lists.pptx
Data Structures_Linear data structures Linked Lists.pptx
RushaliDeshmukh2
 
Artificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptxArtificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptx
aditichinar
 
Compiler Design_Lexical Analysis phase.pptx
Compiler Design_Lexical Analysis phase.pptxCompiler Design_Lexical Analysis phase.pptx
Compiler Design_Lexical Analysis phase.pptx
RushaliDeshmukh2
 
DSP and MV the Color image processing.ppt
DSP and MV the  Color image processing.pptDSP and MV the  Color image processing.ppt
DSP and MV the Color image processing.ppt
HafizAhamed8
 
Artificial Intelligence introduction.pptx
Artificial Intelligence introduction.pptxArtificial Intelligence introduction.pptx
Artificial Intelligence introduction.pptx
DrMarwaElsherif
 
theory-slides-for react for beginners.pptx
theory-slides-for react for beginners.pptxtheory-slides-for react for beginners.pptx
theory-slides-for react for beginners.pptx
sanchezvanessa7896
 
new ppt artificial intelligence historyyy
new ppt artificial intelligence historyyynew ppt artificial intelligence historyyy
new ppt artificial intelligence historyyy
PianoPianist
 
15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...
IJCSES Journal
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
DATA-DRIVEN SHOULDER INVERSE KINEMATICS YoungBeom Kim1 , Byung-Ha Park1 , Kwa...
charlesdick1345
 
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptxLidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
RishavKumar530754
 
New Microsoft PowerPoint Presentation.pdf
New Microsoft PowerPoint Presentation.pdfNew Microsoft PowerPoint Presentation.pdf
New Microsoft PowerPoint Presentation.pdf
mohamedezzat18803
 
Introduction to FLUID MECHANICS & KINEMATICS
Introduction to FLUID MECHANICS &  KINEMATICSIntroduction to FLUID MECHANICS &  KINEMATICS
Introduction to FLUID MECHANICS & KINEMATICS
narayanaswamygdas
 
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
inmishra17121973
 
Data Structures_Introduction to algorithms.pptx
Data Structures_Introduction to algorithms.pptxData Structures_Introduction to algorithms.pptx
Data Structures_Introduction to algorithms.pptx
RushaliDeshmukh2
 
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E..."Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
Infopitaara
 
Metal alkyne complexes.pptx in chemistry
Metal alkyne complexes.pptx in chemistryMetal alkyne complexes.pptx in chemistry
Metal alkyne complexes.pptx in chemistry
mee23nu
 
Ad

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
  • 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