Skip to content

Commit d859382

Browse files
Sashko Stubailoleebyron
Sashko Stubailo
authored andcommitted
Add some more things
1 parent 557d1b9 commit d859382

File tree

1 file changed

+108
-1
lines changed

1 file changed

+108
-1
lines changed

site/docs/Learn-Queries.md

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ next: /docs/queries/
99
### Outline
1010

1111
* A simple query
12-
* Fields, arguments, and aliases
12+
* Nesting
13+
* Arguments
14+
* Aliases
1315
* Fragments
1416
* Comments
1517
* Variables
18+
* Operation names
1619
* Directives (skip & include)
1720
* A simple mutation
1821

@@ -136,3 +139,107 @@ fragment comparisonFields on Character {
136139
</script>
137140

138141
You can see how the above query would be pretty repetitive if the fields were repeated. The concept of fragments is frequently used to split complicated application data requirements into smaller chunks, especially when you need to combine lots of UI components with different fragments into one initial data fetch.
142+
143+
### Variables
144+
145+
So far, we have been writing all of our arguments inside the query string. But in most applications, the arguments to fields will be dynamic: For example, there might be a dropdown that lets you select which Star Wars episode you are interested in, or a search field, or a set of filters.
146+
147+
It wouldn't be a good idea to pass these dynamic arguments directly in the query string, because then our client-side code would need to dynamically manipulate the query string at runtime, and serialize it into a GraphQL-specific format. Instead, GraphQL has a first-class way to factor dynamic values out of the query, and pass them as a separate dictionary. These values are called _variables_.
148+
149+
When we start working with variables, we need to do three things:
150+
151+
1. Replace the static value in the query with `$variableName`
152+
2. Declare `$variableName` in our query
153+
3. Pass `variableName: value` in the separate, transport-specific (usually JSON) variables dictionary
154+
155+
Here's what it looks like all together:
156+
157+
```graphql
158+
# as far as I know, this mini GraphiQL thing doesn't have variable support...
159+
query HeroNameAndFriends($episode: Episode) {
160+
hero(episode: $episode) {
161+
name
162+
friends {
163+
name
164+
}
165+
}
166+
}
167+
168+
variables: {
169+
episode: 'JEDI'
170+
}
171+
```
172+
173+
Now, in our client code, we can simply pass a different variable rather than needing to construct an entirely new query. This is also in general a good practice for denoting which arguments in our query are expected to be dynamic - we should never be doing string interpolation to construct queries from user-supplied values.
174+
175+
### Operation name
176+
177+
One thing we also saw in the example above is that our query has acquired a _name_. Up until now, we have been using a shorthand syntax where we omit both the `query` keyword and the query name, but in production apps it's useful to use these to make our code less ambiguous.
178+
179+
Think of this just like a function name in your favorite programming language. For example, in JavaScript we can easily work only with anonymous functions, but when we give a function a name, it's easier to track it down, debug our code, and log when it's called. In the same way, GraphQL query and mutation names, along with fragment names, can be a useful debugging tool on the server side to identify different GraphQL requests.
180+
181+
### Directives: skip and include
182+
183+
We discussed above how variables enable us to avoid doing manual string interpolation to construct dynamic queries. Passing variables in arguments solves a pretty big class of these problems, but we might also need a way to dynamically change the structure and shape of our queries using variables. For example, we can imagine a UI component that has a summarized and detailed view, where one includes more fields than the other.
184+
185+
Let's construct a query for such a component:
186+
187+
```graphql
188+
query Hero($episode: Episode, $withFriends: Boolean) {
189+
hero(episode: $episode) {
190+
name
191+
friends @include(if: $withFriends) {
192+
name
193+
}
194+
}
195+
}
196+
197+
variables: {
198+
episode: 'JEDI',
199+
withFriends: false
200+
}
201+
```
202+
203+
We needed to use a new feature in GraphQL called a _directive_. A directive can be attached to a field or fragment inclusion, and can affect execution of the query in any way the server desires. The core GraphQL specification includes exactly two directives, which must be supported by any spec-compliant GraphQL server implementation:
204+
205+
- `@include(if: Boolean)` Only include this field in the result if the argument is `true`.
206+
- `@skip(if: Boolean)` Skip this field if the argument is `true`.
207+
208+
Directives can be useful to get out of situations where you otherwise would need to do string manipulation to add and remove fields in your query. Server implementations may also add experimental features by defining completely new directives.
209+
210+
### Mutations
211+
212+
Most discussions of GraphQL focus on data fetching, but any complete data platform needs a way to modify server-side data as well.
213+
214+
In REST, any request might end up causing some side-effects on the server, but by convention it's suggested that one doesn't use `GET` requests to modify data. GraphQL is similar - technically any query could be implemented to cause a data write. However, it's useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.
215+
216+
Here's an example of a simple mutation:
217+
218+
```graphql
219+
mutation CreateCharacterInEpisode($name: String!, $appearsIn: Episode!) {
220+
createCharacter(name: $name)
221+
addCharacterToEpisode(name: $name, episode: $appearsIn)
222+
}
223+
```
224+
225+
You can see that a mutation can contain multiple fields, just like a query. There's one important distinction between queries, and mutations, other than the name:
226+
227+
**While query fields are executed in parallel, mutation fields run in series, one after the other.**
228+
229+
This means that even though we sent `createCharacter` and `addCharacterToEpisode` in one request, the first is guaranteed to finish before the second begins, ensuring that we create the character before trying to add it an episode.
230+
231+
#### Returning data from mutations
232+
233+
Just like in queries, you can ask for nested fields in the mutation result. This can be useful for fetching the new state of an object after an update:
234+
235+
```graphql
236+
mutation IncrementCredits($characterId: ID!) {
237+
incrementCredits(characterId: $characterId) {
238+
totalCredits
239+
}
240+
}
241+
```
242+
243+
In this case, the `incrementCredits` mutation field returns a `Character` object, so we can query the new value of `totalCredits` after giving that character some more credits. Otherwise, we would have needed to send two requests - one to update the credits, and another to get the new value - or guess at the new amount based on outdated data.
244+
245+
That's all! Now you know everything you need to know about GraphQL queries and mutations to build a pretty good application. For more advanced features and tips, check out the advanced section.

0 commit comments

Comments
 (0)