Cannula Documentation¶
Using GraphQL you can simplify your web application stack and reduce dependencies to achieve the same customer experience without regret. By using just a few core libraries you can increase productivity and make your application easier to maintain.
Our Philosophy:
Make your site easy to maintain.
Document your code.
Don’t lock yourself into a framework.
Be happy!
Listen to me talk about GraphQL:
Installation¶
Requirements:
Python 3.6+
Use pip:
$ pip3 install cannula
Quick Start¶
Here is a small hello world example:
import logging
import typing
import sys
import cannula
from cannula.middleware import DebugMiddleware
SCHEMA = cannula.gql("""
type Message {
text: String
}
type Query {
hello(who: String): Message
}
""")
logging.basicConfig(level=logging.DEBUG)
api = cannula.API(
__name__,
schema=SCHEMA,
middleware=[
DebugMiddleware()
]
)
class Message(typing.NamedTuple):
text: str
# The query resolver takes a source and info objects
# and any arguments defined by the schema. Here we
# only accept a single argument `who`.
@api.resolver('Query')
async def hello(source, info, who):
return Message(f"Hello, {who}!")
# Pre-parse your query to speed up your requests.
# Here is an example of how to pass arguments to your
# query functions.
SAMPLE_QUERY = cannula.gql("""
query HelloWorld ($who: String!) {
hello(who: $who) {
text
}
}
""")
who = 'world'
if len(sys.argv) > 1:
who = sys.argv[1]
print(api.call_sync(SAMPLE_QUERY, variables={'who': who}))
Dataloaders¶
TODO: example dataloader
Testing Your Code¶
Since GraphQL is typed it is trivial to mock the responses to any Query or Mutation. Cannula provides a MockMiddleware which can mock all types or only select few to provide flexibility when writing your tests. Here is a small example:
import cannula
from cannula.middleware import MockMiddleware
schema = cannula.gql("""
type Brocoli {
taste: String
}
type Message {
text: String
number: Int
float: Float
isOn: Boolean
id: ID
brocoli: Brocoli
}
type Query {
mockity: [Message]
}
""")
sample_query = cannula.gql("""{
mockity {
text
number
float
isOn
id
brocoli {
taste
}
}
}
""")
default = cannula.API(
__name__,
schema=schema,
middleware=[
MockMiddleware()
],
)
print(f'''
Results with the default 'mock_all=True'. Since the result
is a list you will get a random number of results unless
you specify '__list_length' in mock_objects:
{default.call_sync(sample_query).data}
''')
custom_mocks = {
'String': 'This will be used for all Strings',
'Int': 42,
'Brocoli': {
'taste': "Delicious"
},
'Query': {
'mockity': [
{'isOn': False, 'brocoli': {}}
]
}
}
custom = cannula.API(
__name__,
schema=schema,
middleware=[
MockMiddleware(
mock_objects=custom_mocks,
mock_all=True
),
],
)
print(f'''
Custom `mock_objects` with `mock_all=True` will return
a fake result for every field:
{custom.call_sync(sample_query).data}
''')
limited_mocks = cannula.API(
__name__,
schema=schema,
middleware=[
MockMiddleware(
mock_objects=custom_mocks,
mock_all=False
),
],
)
print(f'''
Limited mocks with `mock_all=False` will only return
fake results for fields mocked in `mock_objects`:
{limited_mocks.call_sync(sample_query).data}
''')