← Back to all tutorials

Mutations (Adding & Deleting Data)

Learn how to modify data with GraphQL mutations — adding new records and deleting existing ones.

Mutations — Adding & Deleting Data

So far we've only been reading data with queries. Mutations allow us to create, update, and delete data. Let's learn how!

What Are Mutations?

Mutations are GraphQL's way of modifying data on the server. They work just like queries but are used for write operations. By convention, they're defined under the Mutation type in your schema.

Defining Mutations in the Schema

First, we need an input type for structured input and mutation definitions:

type Mutation {
  addGame(game: AddGameInput!): Game
  deleteGame(id: ID!): [Game]
}

input AddGameInput {
  title: String!
  platform: [String!]!
}

Why Input Types?

Input types (input) are separate from regular types (type) because:

  • They can only contain scalar fields and other input types
  • They keep mutation arguments organized
  • You often don't want to include fields like id (auto-generated) or computed fields

Writing Mutation Resolvers

Add Game

import { v4 as uuidv4 } from 'uuid';

const resolvers = {
  // ... Query resolvers ...

  Mutation: {
    addGame(_, args) {
      const newGame = {
        id: uuidv4(),        // Generate a unique ID
        ...args.game,        // Spread the input fields
      };
      games.push(newGame);   // Add to our data store
      return newGame;        // Return the new game
    },
  },
};

Delete Game

const resolvers = {
  Mutation: {
    addGame(_, args) {
      const newGame = { id: uuidv4(), ...args.game };
      games.push(newGame);
      return newGame;
    },

    deleteGame(_, args) {
      games = games.filter(g => g.id !== args.id);
      return games;  // Return the remaining games
    },
  },
};

Running Mutations

Adding a Game

mutation AddGame($game: AddGameInput!) {
  addGame(game: $game) {
    id
    title
    platform
  }
}

Variables:

{
  "game": {
    "title": "Hogwarts Legacy",
    "platform": ["PS5", "Xbox", "PC"]
  }
}

Response:

{
  "data": {
    "addGame": {
      "id": "a1b2c3d4-...",
      "title": "Hogwarts Legacy",
      "platform": ["PS5", "Xbox", "PC"]
    }
  }
}

Deleting a Game

mutation DeleteGame($id: ID!) {
  deleteGame(id: $id) {
    id
    title
  }
}
{
  "id": "1"
}

Mutation Best Practices

  • Always return data — return the created/modified object so the client can update its cache
  • Use input types — keep mutation arguments organized with input types
  • Validate inputs — check data before modifying your store
  • Handle errors gracefully — throw meaningful errors for invalid operations

Adding a Delete Review and Delete Author

Extend your mutations to handle all types:

type Mutation {
  addGame(game: AddGameInput!): Game
  deleteGame(id: ID!): [Game]
  addReview(review: AddReviewInput!): Review
  deleteReview(id: ID!): [Review]
}

input AddReviewInput {
  rating: Int!
  content: String!
  game_id: ID!
  author_id: ID!
}

Key Takeaways

  • Mutations are used for create, update, and delete operations
  • Use input types for structured mutation arguments
  • Mutation resolvers modify data and return the result
  • Always return useful data from mutations for client cache updates
  • The mutation syntax is similar to queries but uses the mutation keyword

Next episode: Update Mutation — modifying existing data!