Mutations Done Right
You'll learn to
- -Design GraphQL mutations with dedicated input types and a consistent naming convention
- -Return enough information from a mutation for the client to update its local state without a follow-up query
Mutations are GraphQL's equivalent of REST's POST/PUT/PATCH/DELETE - the mechanism for changing data rather than just reading it. Like queries, mutations are defined on their own root type, and a few conventions separate mutations that are pleasant to use from ones that fight every client that calls them.
Input Types, Not Raw Arguments
input CreateUserInput {
name: String!
email: String!
age: Int
}
type Mutation {
createUser(input: CreateUserInput!): User!
}A mutation could accept each field as a separate top-level argument (`createUser(name: String!, email: String!, age: Int): User!`), but a dedicated `input` type keeps the mutation's signature stable as fields are added - a new optional field on the input type doesn't change the mutation's own signature, whereas adding a new top-level argument does. This is the GraphQL equivalent of the DTO discipline from the REST modules: a deliberate, versioned boundary instead of the internal shape leaking directly into the call site.
Naming: Verb-Noun, Consistently
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): DeleteUserPayload!
}Just as REST benefits from consistent resource naming, GraphQL mutations benefit from a consistent verb-noun pattern (`createX`, `updateX`, `deleteX`) applied uniformly - a client integrating against the API can predict a mutation's name and shape from the pattern, instead of needing to look up each one individually because naming varies field by field.
Returning Enough to Avoid a Follow-Up Query
type DeleteUserPayload {
deletedId: ID!
success: Boolean!
}
mutation {
deleteUser(id: "42") {
deletedId
success
}
}A mutation should return enough information for the client to update its own local cache or UI state without an immediate follow-up query - `createUser` returning the full new `User` object (including its server-assigned `id`) lets the client add it to a local list directly; `deleteUser` returning the deleted ID lets the client remove exactly that item from a local cache, which is why even a delete mutation - conceptually "nothing to return" in REST's 204 sense - typically returns a small payload in GraphQL rather than nothing at all.
This return-enough-for-local-state-updates convention is specifically important for GraphQL clients using a normalized cache (like Apollo Client or Relay) - those caches update automatically based on IDs present in a mutation response, so omitting them forces a wasteful, avoidable follow-up query just to keep the UI in sync.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Design Mutation Station in the API Design Lab's GraphQL Mastery act.