Mutations

Last updated 9 months ago

The API offers

  • Simple mutations: Create, update, upsert and delete single nodes of a certain object type

  • Batch mutations: Update and delete many nodes of a certain model

  • Relation mutations: Connect, disconnect, create, update and upsert nodes across relations

In general, the GraphCMS API is generated based on the content models. To explore the operations in your API, you can use the API Explorer.

In the following, we will explore example queries based on a GraphCMS service with this data model:

type Post {
id: ID! @unique
title: String!
author: User!
}
‚Äč
type User {
id: ID! @unique
age: Int
email: String! @unique
name: String!
posts: [Post!]!
}

Object mutations

We can use model mutations to modify single nodes of a certain model.

Creating nodes

Here, we use the createUser mutation to create a new user:

# Create a new user
mutation {
createUser(
data: {
age: 42
email: "zeus@example.com"
name: "Zeus"
}
) {
id
name
}
}

Note: All required fields without a default value need to be specified in the data input object.

Updating nodes

We can use updateUser to change the email and name. Note that we're selecting the node to update using the where argument:

mutation {
updateUser(
data: {
email: "zeus2@example.com"
name: "Zeus2"
}
where: {
email: "zeus@example.com"
}
) {
id
name
}
}

Upserting nodes

When we want to either update an existing node, or create a new one in a single mutation, we can use upsert mutations.

Here, we use upsertUser to update the User with a certain email, or create a new User if a User with that email doesn't exist yet:

# Upsert a user
mutation {
upsertUser(
where: {
email: "zeus@example.com"
}
create: {
email: "zeus@example.com"
age: 42
name: "Zeus"
}
update: {
name: "Another Zeus"
}
) {
name
}
}

Note: create and update are of the same type as the data object in the createUser and updateUser mutations.

Deleting nodes

To delete nodes, all we have to do is to use the select the node(s) to be deleted in a delete mutation.

Here, we use deleteUser to delete a user by its id:

mutation {
deleteUser(where: {
id: "cjcdi63l20adx0146vg20j1ck"
}) {
id
name
email
}
}

Because email is also annotated with the unique directive, we can also selected (and thus delete) User nodes by their email:

mutation {
deleteUser(where: {
email: "zeus@example.com"
}) {
id
name
email
}
}

Nested mutations

We can use create and update model mutations to modify nodes across relations at the same time. This is referred to as nested mutations and is executed transactionally.

Overview

Several nested mutation arguments exist:

  • create

  • update

  • upsert

  • delete

  • connect

  • disconnect

Their availability and the exact behaviour depends on the following two parameters:

  • the type of the parent mutation

    • create mutation

    • update mutation

    • upsert mutation

  • the type of the relation

    • optional to-one relation

    • required to-one

    • to-many relation

For example

  • a create mutation only exposes nested create and connect mutations

  • an update mutation exposes update, upsert mutations for a required to-one relation

Examples

Rather than mapping out all possible scenarios at this point, we provide a list of examples.

It's recommended to explore the behaviour of different nested mutations by using the API explorer.

We can use the connect action within a nested input object field to connect to one or more related nodes.

Here, we are creating a new Post and connect to an existing author via the unique email field. In this case, connect provides a way for node selection:

# Create a post and connect it to an author
mutation {
createPost(data: {
title: "This is a draft"
status: DRAFT
author: {
connect: {
email: "zeus@example.com"
}
}
}) {
id
author {
name
}
}
}

If we provide a create argument instead of connect within author, we would create a related author and at the same time connect to it, instead of connecting to an existing author.

When creating a User instead of a Post, we can actually create and connect to multiple Post nodes at the same time, because User has a to-many relation Post.

Here, we are creating a new User and directly connect it to several new and existing Post nodes:

# Create a user, create and connect new posts, and connect to existing posts
mutation {
createUser(
data: {
email: "zeus@example.com"
name: "Zeus"
age: 42
posts: {
create: [{
status: PUBLISHED
title: "First blog post"
}, {
status: PUBLISHED
title: "Second blog post"
}]
connect: [{
id: "cjcdi63j80adw0146z7r59bn5"
}, {
id: "cjcdi63l80ady014658ud1u02"
}]
}
}
) {
id
posts {
id
}
}
}

When updating nodes, you can update one or more related nodes at the same time.

mutation {
updateUser(
data: {
posts: {
update: [{
where: {
id: "cjcf1cj0r017z014605713ym0"
}
data: {
title: "Hello World"
}
}]
}
}
where: {
id: "cjcf1cj0c017y01461c6enbfe"
}
) {
id
}
}

Note that update accepts a list of objects with where and data fields suitable for the updatePost mutation.

Nested upserting works similarly:

mutation {
updatePost(
where: {
id: "cjcf1cj0r017z014605713ym0"
}
data: {
author: {
upsert: {
where: {
id: "cjcf1cj0c017y01461c6enbfe"
}
update: {
email: "zeus2@example.com"
name: "Zeus2"
}
create: {
email: "zeus@example.com"
name: "Zeus"
}
}
}
}
) {
id
}
}

When updating nodes, you can delete one or more related nodes at the same time. In this case, delete provides a way node selection:

mutation {
updateUser(
data: {
posts: {
delete: [{
id: "cjcf1cj0u01800146jii8h8ch"
}, {
id: "cjcf1cj0u01810146m84cnt34"
}]
}
}
where: {
id: "cjcf1cj0c017y01461c6enbfe"
}
) {
id
}
}

Scalar list mutations

When an object type has a field that is has a scalar list as its type, there are a number of special mutations available.

In the following data model, the User type has three such fields:

type User {
id: ID! @unique
scores: [Int!]! # scalar list for integers
friends: [String!]! # scalar list for strings
coinFlips: [Boolean!]! # scalar list for booleans
}

Creating nodes

When creating a new node of type User, a list of values can be provided for each scalar list field using set.

Example

mutation {
createUser(data: {
scores: { set: [1, 2, 3] }
friends: { set: ["Sarah", "Jane"] }
throws: { set: [false, false] }
}) {
id
}
}

Updating nodes

When updating an existing node of type User, a number of additional operations can be performed on the scalar list fields:

  • set: Override the existing list with an entirely new list.

  • push (coming soon): Add one or more elements anywhere in the list.

  • pop (coming soon): Remove one or more elements from the beginning or the end of the list.

  • remove (coming soon): Remove all elements from the list that match a given filter.

push,popandremove` are not yet implemented. If you're curious what these are going to look like, you can get a preview in the respective specification.

set

Each scalar list field takes an object with a set field in an update-mutation. The value of that field is a single value or a list of the corresponding scalar type.

Examples

Set the scores of an existing User node to [1]:

mutation {
updateUser(
where: {
id: "cjd4lfdyww0h00144zst9alur"
}
data: {
scores: {
set: 1
}
}
) {
id
}
}

Set the scores of an existing User node to [10,20,30]:

mutation {
updateUser(
where: {
id: "cjd4lfdyww0h00144zst9alur"
}
data: {
scores: {
set: [10,20,30]
}
}
) {
id
}
}

Batch Mutations

Batch mutations are useful to update or delete many nodes at once. The returned data only contains the count of affected nodes.

For updating many nodes, you can select the affected nodes using the where argument, while you specify the new values with data. All nodes will be updated to the same value.

Here, we are publishing all unpublished Post nodes that were created in 2017:

mutation {
updateManyPosts(
where: {
createdAt_gte: "2017"
createdAt_lt: "2018"
status: DRAFT
}
data: {
status: PUBLISHED
}
) {
count
}
}

Here, we are deleting all unpublished Post nodes of a certain author:

mutation {
deleteManyPosts(
where: {
status: DRAFT
author: {
name: "Zeus"
}
}
) {
count
}
}