@@ -2,33 +2,225 @@ Compose queries dynamically
2
2
===========================
3
3
4
4
Instead of providing the GraphQL queries as a Python String, it is also possible to create GraphQL queries dynamically.
5
- Using the DSL module, we can create a query using a Domain Specific Language which is created from the schema.
5
+ Using the :mod: `DSL module <gql.dsl> `, we can create a query using a Domain Specific Language which is created from the schema.
6
+
7
+ The following code:
6
8
7
9
.. code-block :: python
8
10
9
- from gql.dsl import DSLSchema
11
+ ds = DSLSchema(StarWarsSchema)
12
+
13
+ query = dsl_gql(
14
+ DSLQuery(
15
+ ds.Query.hero.select(
16
+ ds.Character.id,
17
+ ds.Character.name,
18
+ ds.Character.friends.select(ds.Character.name),
19
+ )
20
+ )
21
+ )
22
+
23
+ will generate a query equivalent to:
24
+
25
+ .. code-block :: python
26
+
27
+ query = gql("""
28
+ query {
29
+ hero {
30
+ id
31
+ name
32
+ friends {
33
+ name
34
+ }
35
+ }
36
+ }
37
+ """ )
38
+
39
+ How to use
40
+ ----------
41
+
42
+ First generate the root using the :class: `DSLSchema <gql.dsl.DSLSchema> `::
43
+
44
+ ds = DSLSchema(client.schema)
45
+
46
+ Then use auto-generated attributes of the :code: `ds ` instance
47
+ to get a root type (Query, Mutation or Subscription).
48
+ This will generate a :class: `DSLType <gql.dsl.DSLType> ` instance::
49
+
50
+ ds.Query
51
+
52
+ From this root type, you use auto-generated attributes to get a field.
53
+ This will generate a :class: `DSLField <gql.dsl.DSLField> ` instance::
54
+
55
+ ds.Query.hero
56
+
57
+ hero is a GraphQL object type and needs children fields. By default,
58
+ there is no children fields selected. To select the fields that you want
59
+ in your query, you use the :meth: `select <gql.dsl.DSLField.select> ` method.
60
+
61
+ To generate the children fields, we use the same method as above to auto-generate the fields
62
+ from the :code: `ds ` instance
63
+ (ie :code: `ds.Character.name ` is the field `name ` of the type `Character `)::
64
+
65
+ ds.Query.hero.select(ds.Character.name)
10
66
11
- client = Client(schema = StarWarsSchema)
12
- ds = DSLSchema(client)
67
+ The select method return the same instance, so it is possible to chain the calls::
13
68
14
- query_dsl = ds.Query.hero.select(
69
+ ds.Query.hero.select(ds.Character.name).select(ds.Character.id)
70
+
71
+ Or do it sequencially::
72
+
73
+ hero_query = ds.Query.hero
74
+
75
+ hero_query.select(ds.Character.name)
76
+ hero_query.select(ds.Character.id)
77
+
78
+ As you can select children fields of any object type, you can construct your complete query tree::
79
+
80
+ ds.Query.hero.select(
15
81
ds.Character.id,
16
82
ds.Character.name,
17
- ds.Character.friends.select(ds.Character.name, ),
83
+ ds.Character.friends.select(ds.Character.name),
18
84
)
19
85
20
- will create a query equivalent to:
86
+ Once your root query fields are defined, you can put them in an operation using
87
+ :class: `DSLQuery <gql.dsl.DSLQuery> `,
88
+ :class: `DSLMutation <gql.dsl.DSLMutation> ` or
89
+ :class: `DSLSubscription <gql.dsl.DSLSubscription> `::
21
90
22
- .. code-block :: python
91
+ DSLQuery(
92
+ ds.Query.hero.select(
93
+ ds.Character.id,
94
+ ds.Character.name,
95
+ ds.Character.friends.select(ds.Character.name),
96
+ )
97
+ )
98
+
99
+
100
+ Once your operations are defined,
101
+ use the :func: `dsl_gql <gql.dsl.dsl_gql> ` function to convert your operations into
102
+ a document which will be able to get executed in the client or a session::
103
+
104
+ query = dsl_gql(
105
+ DSLQuery(
106
+ ds.Query.hero.select(
107
+ ds.Character.id,
108
+ ds.Character.name,
109
+ ds.Character.friends.select(ds.Character.name),
110
+ )
111
+ )
112
+ )
113
+
114
+ result = client.execute(query)
115
+
116
+ Arguments
117
+ ^^^^^^^^^
118
+
119
+ It is possible to add arguments to any field simply by calling it
120
+ with the required arguments::
121
+
122
+ ds.Query.human(id="1000").select(ds.Human.name)
123
+
124
+ It can also be done using the :meth: `args <gql.dsl.DSLField.args> ` method::
125
+
126
+ ds.Query.human.args(id="1000").select(ds.Human.name)
23
127
24
- hero {
25
- id
26
- name
27
- friends {
28
- name
29
- }
128
+ Aliases
129
+ ^^^^^^^
130
+
131
+ You can set an alias of a field using the :meth: `alias <gql.dsl.DSLField.alias> ` method::
132
+
133
+ ds.Query.human.args(id=1000).alias("luke").select(ds.Character.name)
134
+
135
+ It is also possible to set the alias directly using keyword arguments of an operation::
136
+
137
+ DSLQuery(
138
+ luke=ds.Query.human.args(id=1000).select(ds.Character.name)
139
+ )
140
+
141
+ Or using keyword arguments in the :meth: `select <gql.dsl.DSLField.select> ` method::
142
+
143
+ ds.Query.hero.select(
144
+ my_name=ds.Character.name
145
+ )
146
+
147
+ Mutations
148
+ ^^^^^^^^^
149
+
150
+ For the mutations, you need to start from root fields starting from :code: `ds.Mutation `
151
+ then you need to create the GraphQL operation using the class
152
+ :class: `DSLMutation <gql.dsl.DSLMutation> `. Example::
153
+
154
+ query = dsl_gql(
155
+ DSLMutation(
156
+ ds.Mutation.createReview.args(
157
+ episode=6, review={"stars": 5, "commentary": "This is a great movie!"}
158
+ ).select(ds.Review.stars, ds.Review.commentary)
159
+ )
160
+ )
161
+
162
+ Subscriptions
163
+ ^^^^^^^^^^^^^
164
+
165
+ For the subscriptions, you need to start from root fields starting from :code: `ds.Subscription `
166
+ then you need to create the GraphQL operation using the class
167
+ :class: `DSLSubscription <gql.dsl.DSLSubscription> `. Example::
168
+
169
+ query = dsl_gql(
170
+ DSLSubscription(
171
+ ds.Subscription.reviewAdded(episode=6).select(ds.Review.stars, ds.Review.commentary)
172
+ )
173
+ )
174
+
175
+ Multiple fields in an operation
176
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
177
+
178
+ It is possible to create an operation with multiple fields::
179
+
180
+ DSLQuery(
181
+ ds.Query.hero.select(ds.Character.name),
182
+ hero_of_episode_5=ds.Query.hero(episode=5).select(ds.Character.name),
183
+ )
184
+
185
+ Operation name
186
+ ^^^^^^^^^^^^^^
187
+
188
+ You can set the operation name of an operation using a keyword argument
189
+ to :func: `dsl_gql <gql.dsl.dsl_gql> `::
190
+
191
+ query = dsl_gql(
192
+ GetHeroName=DSLQuery(ds.Query.hero.select(ds.Character.name))
193
+ )
194
+
195
+ will generate the request::
196
+
197
+ query GetHeroName {
198
+ hero {
199
+ name
200
+ }
30
201
}
31
202
32
- .. warning ::
203
+ Multiple operations in a document
204
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
205
+
206
+ It is possible to create an Document with multiple operations::
207
+
208
+ query = dsl_gql(
209
+ operation_name_1=DSLQuery( ... ),
210
+ operation_name_2=DSLQuery( ... ),
211
+ operation_name_3=DSLMutation( ... ),
212
+ )
213
+
214
+ Executable examples
215
+ -------------------
216
+
217
+ Async example
218
+ ^^^^^^^^^^^^^
219
+
220
+ .. literalinclude :: ../code_examples/aiohttp_async_dsl.py
221
+
222
+ Sync example
223
+ ^^^^^^^^^^^^^
224
+
225
+ .. literalinclude :: ../code_examples/requests_sync_dsl.py
33
226
34
- Please note that the DSL module is still considered experimental in GQL 3 and is subject to changes
0 commit comments