Skip to content

Query Executor

Pygraphy can be used as a GraphQL schema declaration and query executor library, same with graphql-core. Call the execute method of a custom Schema and get the query response.

import asyncio
import pygraphy
from typing import Optional


class Patron(pygraphy.Object):
    id: str
    name: str
    age: int


class Query(pygraphy.Query):

    @pygraphy.field
    def patron(self) -> Patron:
        return Patron(id='1', name='Gwo', age=25)

    @pygraphy.field
    def exception(self, content: str) -> str:
        raise RuntimeError(content)


class Schema(pygraphy.Schema):
    query: Optional[Query]


query = """
    query something {
      patron {
        id
        name
        age
      }
    }
"""

loop = asyncio.get_event_loop()
result = loop.run_until_complete(Schema.execute(query))
assert result == {
    'errors': None,
    'data': {'patron': {'id': '1', 'name': 'Gwo', 'age': 25}}
}

the Schema.execute method is defined like below:

async def execute(
    cls,
    query: str,
    variables: Optional[Dict[str, Any]] = None,
    request: Optional[Any] = None,
    serialize: bool = False
)

Parameters:

  • query: GraphQL query string.
  • variables: A dict of query variables, pass it if there are some variables in query string.
  • request: the request instance, it could be got from query context in resolver fields. It is useful if you want to get the request info in resolvers, such as HTTP headers.
  • serialize: If it is true, executor would return a JSON string which as already been dumped. Return a Python dict result as default.

Asynchronous Executor

Pygraphy fully supports asyncio, the Python native parallel model. Just define the resolver field as a coroutine function, Pygraphy would automatically executes it as a coroutine task. All resolver fields in a same Object would be executed parallel.

import asyncio
import pygraphy
from typing import Optional


global_var = False


class Query(pygraphy.Query):

    @pygraphy.field
    async def foo(self) -> bool:
        global global_var
        result = global_var
        await asyncio.sleep(0.1)
        global_var = True
        return result

    @pygraphy.field
    async def bar(self) -> bool:
        global global_var
        result = global_var
        await asyncio.sleep(0.1)
        global_var = True
        return result


class Schema(pygraphy.Schema):
    query: Optional[Query]


query = """
    query test {
        foo
        bar
    }
"""


loop = asyncio.get_event_loop()
result = loop.run_until_complete(Schema.execute(query))
# Obviously, foo and bar both return False, cause they are executed parallel.
assert result == {
    'errors': None,
    'data': {'foo': False, 'bar': False}
}

Attention: do not mix asynchronous resolvers and non-asynchronous resolvers together. the non-asynchronous resolvers would block the query process, it is a design of Python asyncio.