1.4: Mutations
1.4: Mutations
Any complete API specification needs to offer the ability not only to query data, but also to create and update it.
Any API backend could, of course, be programmed to make data changes in response to any particular request, but a good protocol
will have a formal separation between requests that do and do not alter data. REST convention includes the expectation that
GET requests will only query data, while POST or PUT requests will change it. In the case of GraphQL, data-modifying queries
are distinguished by the mutation
keyword that corresponds with a different root type in the schema defined at the server.
While we can't try mutations live (swapi-graphql exposes none), we can look at a mutation for creating a Person
record in the imaginary schema we've been using:
mutation doCreatePerson(
$person: PersonInput!,
$favoriteFoodIds: [ID],
$friendIds: [ID]
) {
createPerson(
person: $person,
favoriteFoodIds: $favoriteFoodIds,
friendIds: $friendIds
) {
id
name
createdAt
}
}
We could imagine the above mutation being sent in a request along with the following variables dictionary:
{
"person": {
"name": "Sally",
"height": 68
},
"favoriteFoodIds": [
"123",
"456"
],
"friendIds": [
"789"
]
}
And finally, we might receive a response like this:
{
"data": {
"createPerson": {
"id": "67890",
"name": "Sally",
"createdAt": "2023-01-01T12:30:01.000000Z"
}
}
}
The chief thing to note about the above example is that, apart from the use of the mutation
keyword instead of query
,
the syntax is identical to a query! Just like queries, the mutation includes:
- An arbitrary operation name (
doCreatePerson
) - A list of variables (e.g.,
$person
) - An initial field (
createPerson
) with arguments (e.g.,person
, set to the value of$person
) in parentheses - A sub-selection of fields in braces
The fields sub-selection allows you to flexibly define the fields you would like returned (from what our imaginary schema
presumably defines as the type of createPerson
- the Person
type) after the mutation is completed. Thus we have one
unified syntax, and there is very little new to learn for mutations.
We've noted how fields defined in a GraphQL schema start on a root type for queries (usually called Query
). Similarly,
another root type exists for mutations (usually called, unsurprisingly, Mutation
). Our example above presumes a field
called createPerson
that has been defined on that root type.
A few other notes about the above example:
- The type for our
$person
variable is specified asPersonInput
. When non-scalar types are available for field arguments, their definitions are separate from the usual object types returned from queries. - The
!
character suffixingPersonInput
indicates the variable is required. - The square brackets (
[]
) around theID
type specified for$favoriteFoodIds
and$friendIds
indicate an array of that type rather than a single value.