Skip to content

Commit 082186c

Browse files
committed
Added dataloader docs
1 parent b71a2cb commit 082186c

File tree

3 files changed

+141
-33
lines changed

3 files changed

+141
-33
lines changed

docs/execution/dataloader.rst

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
Dataloader
2+
==========
3+
4+
DataLoader is a generic utility to be used as part of your application's
5+
data fetching layer to provide a simplified and consistent API over
6+
various remote data sources such as databases or web services via batching
7+
and caching.
8+
9+
10+
Batching
11+
--------
12+
13+
Batching is not an advanced feature, it's DataLoader's primary feature.
14+
Create loaders by providing a batch loading function.
15+
16+
.. code:: python
17+
18+
from promise import Promise
19+
from promise.dataloader import DataLoader
20+
21+
class UserLoader(DataLoader):
22+
def batch_load_fn(self, keys):
23+
# Here we return a promise that will result on the
24+
# corresponding user for each key in keys
25+
return Promise.resolve([get_user(id=key) for key in keys])
26+
27+
28+
A batch loading function accepts an list of keys, and returns a ``Promise``
29+
which resolves to an list of ``values``.
30+
31+
Then load individual values from the loader. ``DataLoader`` will coalesce all
32+
individual loads which occur within a single frame of execution (executed once
33+
the wrapping promise is resolved) and then call your batch function with all
34+
requested keys.
35+
36+
37+
38+
.. code:: python
39+
40+
user_loader = UserLoader()
41+
42+
user_loader.load(1).then(lambda user: user_loader.load(user.best_friend_id))
43+
44+
user_loader.load(2).then(lambda user: user_loader.load(user.best_friend_id))
45+
46+
47+
A naive application may have issued *four* round-trips to a backend for the
48+
required information, but with ``DataLoader`` this application will make at most *two*.
49+
50+
``DataLoader`` allows you to decouple unrelated parts of your application without
51+
sacrificing the performance of batch data-loading. While the loader presents
52+
an API that loads individual values, all concurrent requests will be coalesced
53+
and presented to your batch loading function. This allows your application to
54+
safely distribute data fetching requirements throughout your application and
55+
maintain minimal outgoing data requests.
56+
57+
58+
59+
Using with Graphene
60+
-------------------
61+
62+
DataLoader pairs nicely well with Grapehne/GraphQL. GraphQL fields are designed
63+
to be stand-alone functions. Without a caching or batching mechanism, it's easy
64+
for a naive GraphQL server to issue new database requests each time a field is resolved.
65+
66+
Consider the following GraphQL request:
67+
68+
69+
.. code::
70+
71+
{
72+
me {
73+
name
74+
bestFriend {
75+
name
76+
}
77+
friends(first: 5) {
78+
name
79+
bestFriend {
80+
name
81+
}
82+
}
83+
}
84+
}
85+
86+
87+
Naively, if ``me``, ``bestFriend`` and ``friends`` each need to request the backend,
88+
there could be at most 13 database requests!
89+
90+
91+
When using DataLoader, we could define the User type using our previous example with
92+
learer code and at most 4 database requests, and possibly fewer if there are cache hits.
93+
94+
95+
.. code:: python
96+
97+
class User(graphene.ObjectType):
98+
name = graphene.String()
99+
best_friend = graphene.Field(lambda: User)
100+
friends = graphene.List(lambda: User)
101+
102+
def resolve_best_friend(self, args, context, info):
103+
return user_loader.load(self.best_friend_id)
104+
105+
def resolve_friends(self, args, context, info):
106+
return user_loader.load_many(self.friend_ids)

docs/execution/execute.rst

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Executing a query
2+
=================
3+
4+
5+
For executing a query a schema, you can directly call the ``execute`` method on it.
6+
7+
8+
.. code:: python
9+
10+
schema = graphene.Schema(...)
11+
result = schema.execute('{ name }')
12+
13+
``result`` represents he result of execution. ``result.data`` is the result of executing the query, ``result.errors`` is ``None`` if no errors occurred, and is a non-empty list if an error occurred.
14+
15+
16+
Context
17+
_______
18+
19+
You can pass context to a query via ``context_value``.
20+
21+
22+
.. code:: python
23+
24+
class Query(graphene.ObjectType):
25+
name = graphene.String()
26+
27+
def resolve_name(self, args, context, info):
28+
return context.get('name')
29+
30+
schema = graphene.Schema(Query)
31+
result = schema.execute('{ name }', context_value={'name': 'Syrus'})
32+

docs/execution/index.rst

+3-33
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,9 @@
22
Execution
33
=========
44

5-
For executing a query a schema, you can directly call the ``execute`` method on it.
6-
7-
8-
.. code:: python
9-
10-
schema = graphene.Schema(...)
11-
result = schema.execute('{ name }')
12-
13-
``result`` represents he result of execution. ``result.data`` is the result of executing the query, ``result.errors`` is ``None`` if no errors occurred, and is a non-empty list if an error occurred.
14-
15-
16-
Context
17-
_______
18-
19-
You can pass context to a query via ``context_value``.
20-
21-
22-
.. code:: python
23-
24-
class Query(graphene.ObjectType):
25-
name = graphene.String()
26-
27-
def resolve_name(self, args, context, info):
28-
return context.get('name')
29-
30-
schema = graphene.Schema(Query)
31-
result = schema.execute('{ name }', context_value={'name': 'Syrus'})
32-
33-
34-
Middleware
35-
__________
36-
375
.. toctree::
38-
:maxdepth: 1
6+
:maxdepth: 2
397

8+
execute
409
middleware
10+
dataloader

0 commit comments

Comments
 (0)