$30 off During Our Annual Pro Sale. View Details »

Graphene

 Graphene

Extending the limits of GraphQL

Syrus Akbary

October 25, 2017
Tweet

More Decks by Syrus Akbary

Other Decks in Technology

Transcript

  1. @syrusakbary Graphene.tools Who am I? • Syrus Akbary, CTO @

    .com • Builder @ Graphene Ecosystem.
  2. @syrusakbary Graphene.tools Overview • Graphene is now two years old

    • Most starred GraphQL framework - 2500★ • Used in 100+ companies in production
 
 

  3. @syrusakbary Graphene.tools Continuous Growth 0 15000 30000 45000 60000 Jan

    Mar May Jul Sept Non-defined version Python2 Python3 Python3 > 50% installs!
  4. @syrusakbary Graphene.tools • Better Resolution API • Simplified codebase, easier

    to contribute • Full advantage of Python 3 (async iterators, class definitions) • Subscriptions! Graphene-Python 2.0
  5. @syrusakbary Graphene.tools Better Resolution API hello(name: String): String def resolve_hello(root,

    args, context, info): return args.get(‘name’) Graphene 1.X def resolve_hello(root, info, name): return name Graphene 2.X
  6. @syrusakbary Graphene.tools Better Resolution API hello(name: String): String def resolve_hello(root,

    args, context, info): return args.get(‘name’) Graphene 1.X def resolve_hello(root, info, name): return name Graphene 2.X
  7. @syrusakbary Graphene.tools Subscriptions from graphql_aiows import AIOHttpWebsocketServer websocket_server = AIOHttpWebsocketServer(schema)

    def graphql_websocket(request): return websocket_server.handle(request) Websocket server class Subscription(graphene.ObjectType): count_to = graphene.Int(max=graphene.Int()) async def resolve_count_to(root, info, max=10): for i in range(max): yield i await asyncio.sleep(1.0) # Sleep 1 sec Subscription type Thanks to async iterators
 in Python 3.6
  8. @syrusakbary Graphene.tools Graphene-JS Goals • Easier to read / less

    code for creating your Schema • Integration with external data sources, starting with Sequelize ORM!
  9. @syrusakbary Graphene.tools Frameworks Comparison type Query { hello(name: String!): String!

    } class Query extends ObjectType { static fields = { hello: new Str({args: {name: new Str()}}), todayIs: new Str(), } hello = ({name}) => `hello ${name}`, todayIs = () => `Wednesday!` } var Query = GraphQLObjectType({ name: Query, fields: { hello: { type: GraphQLString, args: { name: GraphQLString }, resolver: ({name}) => `hello ${name}` }, todayIs: { type: GraphQLString, resolver: () => `Wednesday!` }, } } GraphQL-JS
  10. @syrusakbary Graphene.tools interface UserBase { id: ID name: String }

    type AnonymousUser extends UserBase type RegisteredUser extends UserBase class UserBase extends Interface { static fields = { id: new ID(), name: new String(), } } class AnonymousUser extends ObjectType { static interfaces = [UserBase] } class RegisteredUser extends ObjectType { static interfaces = [UserBase] } var UserBase = GraphQLInterfaceType({ name: UserBase, fields: { id: { type: GraphQLId, }, name: { type: GraphQLString, }, } } var AnonymousUser = GraphQLObjectType({ name: Query, interfaces: [UserBase]. fields: { id: { type: GraphQLId, }, name: { type: GraphQLString, }, } } var RegisteredUser = GraphQLObjectType({ name: Query, interfaces: [UserBase]. fields: { id: { type: GraphQLId, }, name: { type: GraphQLString, }, } } GraphQL-JS
  11. @syrusakbary Graphene.tools ❤ Templates • I’ve been always very interested

    in how template engines work internally. Launched PyJade 6 years ago. • Since then, I’ve been experimenting with a lot of different template engines, from Python to JS.
  12. @syrusakbary Graphene.tools Template Engine Analysis render(template, { "user": { "is_authenticated":

    True, "username": "Peter" } }) Hello, Peter. def render_template(context): value = "" if user.is_authenticated: Value += "Hello, " value += str(user.username) return value Precompile to Native code Execute render function Hello, Peter. Jinja2 {% if user.is_authenticated %} Hello, {{ user.username }}. {% endif %} Render in Runtime {% if user.is_authenticated %} Hello, {{ user.username }}. {% endif %} Django
  13. @syrusakbary Graphene.tools GraphQL Engine Analysis { hello(name: $username) } GraphQL-*

    graphql(query, variables={ "username": "Peter" }) {"hello": "Peter"} def execute_query(root, variables, …): ast, query_type, hello_field, info = … result = {} name = variables["username"] result["hello"] = hello_field.resolver( root, info, name=name ) return result Precompile to Native code Execute query function Quiver { hello(name: $username) } Query in Runtime {"hello": "Peter"}
  14. @syrusakbary Graphene.tools Some benchmarks Simple Query Highly Nested Query Complex

    Query with Fragments (lower is better) 0 ms 400 ms 800 ms 1,200 ms 1,600 ms GraphQL core Quiver
  15. @syrusakbary Graphene.tools More benchmarks • +300.000 resolutions / sec (Python

    - CPython) • +1.000.000 resolutions / sec (Python - pypy)
  16. @syrusakbary Graphene.tools Same principles, multiple languages • This strategy could

    be specially beneficial in interpreted languages. • 5-10x performance: CPython, Ruby • 2-3x performance in JIT-enhanced backends: Pypy, V8, Spidermonkey, Hack …
  17. @syrusakbary Graphene.tools Thanks • Graphene collaborators: • Patrick Armino: DRF

    integration • Jacob Foster: Graphene-Django • Devin Fee: Graphene-AIOHttp • Performance & Optimization feedback: • Marc Tamlyn • Klemen Sever • Side projects: • Nick Schrock: GraphScale • Predrag Gruevski - Kensho technologies: GraphQL-compiler