Back to Blog
Lesson 32 of the GraphQL: Your First GraphQL Schema & Server course
API ArchitectureAugust 19, 20264 min read

GraphQL Mutation Best Practices: Naming and Return Types

Learn how to name GraphQL mutations as verbs and return full objects to ensure seamless client-side cache updates in your API.

GraphQLAPI DesignBest PracticesMutationsWeb Development
Scrabble tiles forming the word 'YIELD' on a marble surface, symbolizing finance and investment.

Previously in this course, we explored Managing Mutation State: Updating Arrays in GraphQL Resolvers, where we touched upon basic state manipulation. While functional, that approach lacked the structural discipline required for production-grade APIs. In this lesson, we’ll move beyond "making it work" to "making it professional" by establishing strict standards for how we name and structure mutations.

The Power of Verbs in Mutation Naming

In GraphQL, Query fields are descriptive nouns (e.g., user, posts) because they fetch existing data. Conversely, Mutation fields must represent actions. If a client is going to change the state of your system, the schema should clearly communicate that intent.

The convention is simple: use a verb-noun pattern.

  • Bad: userUpdate(id: ID!, input: UserInput!)
  • Good: updateUser(id: ID!, input: UserInput!)

By placing the verb first, you create a predictable API surface. When a frontend developer scans your schema, they immediately identify the action, followed by the domain object being affected. This mirrors the logic we see in RESTful API Patterns: Naming Conventions and Status Codes, where HTTP methods (POST, PUT, DELETE) act as the "verbs" for your resources.

Why Return the Mutated Object?

A common mistake for beginners is returning a simple boolean (e.g., success: Boolean) from a mutation. While this tells the client if the operation finished, it forces the client to perform an additional, unnecessary query to synchronize its local cache with the server’s new state.

GraphQL clients like Apollo Client use the id field of an object to normalize and cache data. When you return the fully updated object from your mutation, the client automatically updates its local store.

Worked Example: Refining the Mutation

Let’s look at how to structure a mutation that follows these best practices.

The Schema Definition:

GraphQL
type Mutation {
  # Verb-Noun naming convention
  updateUser(id: ID!, input: UpdateUserInput!): User!
}

type User {
  id: ID!
  username: String!
  email: String!
}

The Resolver Implementation:

JAVASCRIPT
const resolvers = {
  Mutation: {
    updateUser: (_, { id, input }, { dataSources }) => {
      // 1. Perform the update logic
      const updatedUser = dataSources.userAPI.update(id, input);
      
      // 2. Return the full object so the client cache updates automatically
      return updatedUser;
    }
  }
};

By returning the User object, any component currently displaying this user’s profile will re-render instantly without requiring a page refresh or a manual refetch query.

Hands-on Exercise

Modify your current running project's Mutation type. If you have an addPost or updatePost mutation, perform the following:

  1. Rename it to follow the verbNoun pattern (e.g., createPost instead of postCreate).
  2. Ensure the return type is the Object type itself (e.g., Post!) rather than a string or boolean.
  3. Update your resolver to return the newly created or updated object.

Common Pitfalls

  • Over-complicating return types: Avoid returning "Payload" wrappers (like { success: Boolean, user: User }) unless you absolutely need to return metadata, like an error message or a status code. For standard operations, returning the object directly is cleaner and more idiomatic.
  • Ignoring the Cache: If you return only the fields that changed, the client-side cache might become inconsistent. Always return the full object or enough fields to satisfy the client’s fragment requirements.
  • Verb Inconsistency: Don't mix styles. If you use updateUser, don't use deleteUser in one place and userDelete in another. Consistency is the foundation of a developer-friendly API.

FAQ

Q: Should I always return the full object? A: Yes, whenever possible. It simplifies the client-side logic significantly by keeping the local cache in sync with the server.

Q: What if the mutation fails? A: Use standard GraphQL errors (which we will cover in the next lesson) rather than returning a "success" boolean. This keeps your schema focused on the data you expect to receive.

Q: Does this apply to deletions? A: Deletions are a special case. Since the object no longer exists, you typically return the ID of the deleted item. We will explore this in detail in the upcoming lesson on Designing for Deletion.

Recap

Following these best practices ensures your GraphQL API is predictable and efficient. By using naming patterns that favor verbs and returning the full state of mutations, you provide a superior experience for frontend engineers consuming your schema.

Up next: Handling Mutation Errors: Throwing and Returning Messages

Similar Posts