@@ -2,33 +2,225 @@ Compose queries dynamically
22===========================
33
44Instead 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:
68
79.. code-block :: python
810
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)
1066
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::
1368
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(
1581 ds.Character.id,
1682 ds.Character.name,
17- ds.Character.friends.select(ds.Character.name, ),
83+ ds.Character.friends.select(ds.Character.name),
1884 )
1985
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> `::
2190
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)
23127
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+ }
30201 }
31202
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
33226
34- Please note that the DSL module is still considered experimental in GQL 3 and is subject to changes
0 commit comments