際際滷

際際滷Share 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

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

Recently uploaded (20)

Indian Soil Classification System in Geotechnical Engineering
Indian Soil Classification System in Geotechnical EngineeringIndian Soil Classification System in Geotechnical Engineering
Indian Soil Classification System in Geotechnical Engineering
Rajani Vyawahare
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptxMathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
ppkmurthy2006
Cloud Computing concepts and technologies
Cloud Computing concepts and technologiesCloud Computing concepts and technologies
Cloud Computing concepts and technologies
ssuser4c9444
decarbonization steel industry rev1.pptx
decarbonization steel industry rev1.pptxdecarbonization steel industry rev1.pptx
decarbonization steel industry rev1.pptx
gonzalezolabarriaped
Mathematics_behind_machine_learning_INT255.pptx
Mathematics_behind_machine_learning_INT255.pptxMathematics_behind_machine_learning_INT255.pptx
Mathematics_behind_machine_learning_INT255.pptx
ppkmurthy2006
04 MAINTENANCE OF CONCRETE PAVEMENTS.ppt
04  MAINTENANCE OF CONCRETE PAVEMENTS.ppt04  MAINTENANCE OF CONCRETE PAVEMENTS.ppt
04 MAINTENANCE OF CONCRETE PAVEMENTS.ppt
sreenath seenu
CS3451-OPERATING-SYSTEM NOTES ALL123.pdf
CS3451-OPERATING-SYSTEM NOTES ALL123.pdfCS3451-OPERATING-SYSTEM NOTES ALL123.pdf
CS3451-OPERATING-SYSTEM NOTES ALL123.pdf
PonniS7
Turbocor Product and Technology Review.pdf
Turbocor Product and Technology Review.pdfTurbocor Product and Technology Review.pdf
Turbocor Product and Technology Review.pdf
Totok Sulistiyanto
US Patented ReGenX Generator, ReGen-X Quatum Motor EV Regenerative Accelerati...
US Patented ReGenX Generator, ReGen-X Quatum Motor EV Regenerative Accelerati...US Patented ReGenX Generator, ReGen-X Quatum Motor EV Regenerative Accelerati...
US Patented ReGenX Generator, ReGen-X Quatum Motor EV Regenerative Accelerati...
Thane Heins NOBEL PRIZE WINNING ENERGY RESEARCHER
GREEN BULIDING PPT FOR THE REFRENACE.PPT
GREEN BULIDING PPT FOR THE REFRENACE.PPTGREEN BULIDING PPT FOR THE REFRENACE.PPT
GREEN BULIDING PPT FOR THE REFRENACE.PPT
kamalkeerthan61
How to Build a Maze Solving Robot Using Arduino
How to Build a Maze Solving Robot Using ArduinoHow to Build a Maze Solving Robot Using Arduino
How to Build a Maze Solving Robot Using Arduino
CircuitDigest
Frankfurt University of Applied Science urkunde
Frankfurt University of Applied Science urkundeFrankfurt University of Applied Science urkunde
Frankfurt University of Applied Science urkunde
Lisa Emerson
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
slayshadow705
Cyber Security_ Protecting the Digital World.pptx
Cyber Security_ Protecting the Digital World.pptxCyber Security_ Protecting the Digital World.pptx
Cyber Security_ Protecting the Digital World.pptx
Harshith A S
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptxGROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
meneememoo
Piping-and-pipeline-calculations-manual.pdf
Piping-and-pipeline-calculations-manual.pdfPiping-and-pipeline-calculations-manual.pdf
Piping-and-pipeline-calculations-manual.pdf
OMI0721
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVName.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
MerijimArsedelPalmad1
Industrial Valves, Instruments Products Profile
Industrial Valves, Instruments Products ProfileIndustrial Valves, Instruments Products Profile
Industrial Valves, Instruments Products Profile
zebcoeng
TM-ASP-101-RF_Air Press manual crimping machine.pdf
TM-ASP-101-RF_Air Press manual crimping machine.pdfTM-ASP-101-RF_Air Press manual crimping machine.pdf
TM-ASP-101-RF_Air Press manual crimping machine.pdf
ChungLe60
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptxUNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
KesavanT10
Indian Soil Classification System in Geotechnical Engineering
Indian Soil Classification System in Geotechnical EngineeringIndian Soil Classification System in Geotechnical Engineering
Indian Soil Classification System in Geotechnical Engineering
Rajani Vyawahare
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptxMathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
Mathematics behind machine learning INT255 INT255__Unit 3__PPT-1.pptx
ppkmurthy2006
Cloud Computing concepts and technologies
Cloud Computing concepts and technologiesCloud Computing concepts and technologies
Cloud Computing concepts and technologies
ssuser4c9444
decarbonization steel industry rev1.pptx
decarbonization steel industry rev1.pptxdecarbonization steel industry rev1.pptx
decarbonization steel industry rev1.pptx
gonzalezolabarriaped
Mathematics_behind_machine_learning_INT255.pptx
Mathematics_behind_machine_learning_INT255.pptxMathematics_behind_machine_learning_INT255.pptx
Mathematics_behind_machine_learning_INT255.pptx
ppkmurthy2006
04 MAINTENANCE OF CONCRETE PAVEMENTS.ppt
04  MAINTENANCE OF CONCRETE PAVEMENTS.ppt04  MAINTENANCE OF CONCRETE PAVEMENTS.ppt
04 MAINTENANCE OF CONCRETE PAVEMENTS.ppt
sreenath seenu
CS3451-OPERATING-SYSTEM NOTES ALL123.pdf
CS3451-OPERATING-SYSTEM NOTES ALL123.pdfCS3451-OPERATING-SYSTEM NOTES ALL123.pdf
CS3451-OPERATING-SYSTEM NOTES ALL123.pdf
PonniS7
Turbocor Product and Technology Review.pdf
Turbocor Product and Technology Review.pdfTurbocor Product and Technology Review.pdf
Turbocor Product and Technology Review.pdf
Totok Sulistiyanto
GREEN BULIDING PPT FOR THE REFRENACE.PPT
GREEN BULIDING PPT FOR THE REFRENACE.PPTGREEN BULIDING PPT FOR THE REFRENACE.PPT
GREEN BULIDING PPT FOR THE REFRENACE.PPT
kamalkeerthan61
How to Build a Maze Solving Robot Using Arduino
How to Build a Maze Solving Robot Using ArduinoHow to Build a Maze Solving Robot Using Arduino
How to Build a Maze Solving Robot Using Arduino
CircuitDigest
Frankfurt University of Applied Science urkunde
Frankfurt University of Applied Science urkundeFrankfurt University of Applied Science urkunde
Frankfurt University of Applied Science urkunde
Lisa Emerson
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
Structural QA/QC Inspection in KRP 401600 | Copper Processing Plant-3 (MOF-3)...
slayshadow705
Cyber Security_ Protecting the Digital World.pptx
Cyber Security_ Protecting the Digital World.pptxCyber Security_ Protecting the Digital World.pptx
Cyber Security_ Protecting the Digital World.pptx
Harshith A S
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptxGROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
GROUP-3-GRID-CODE-AND-DISTRIBUTION-CODE.pptx
meneememoo
Piping-and-pipeline-calculations-manual.pdf
Piping-and-pipeline-calculations-manual.pdfPiping-and-pipeline-calculations-manual.pdf
Piping-and-pipeline-calculations-manual.pdf
OMI0721
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVName.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
Name.docxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
MerijimArsedelPalmad1
Industrial Valves, Instruments Products Profile
Industrial Valves, Instruments Products ProfileIndustrial Valves, Instruments Products Profile
Industrial Valves, Instruments Products Profile
zebcoeng
TM-ASP-101-RF_Air Press manual crimping machine.pdf
TM-ASP-101-RF_Air Press manual crimping machine.pdfTM-ASP-101-RF_Air Press manual crimping machine.pdf
TM-ASP-101-RF_Air Press manual crimping machine.pdf
ChungLe60
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptxUNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
UNIT 1FUNDAMENTALS OF OPERATING SYSTEMS.pptx
KesavanT10

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