Mutation Response Design

Mutation responses should be designed intentionally rather than simply returning an arbitrary object.

A simple mutation can return the changed resource:

createPost(input: CreatePostInput!): Post!

For more complex operations, a payload type can be useful:

type CreatePostPayload {
  post: Post
  errors: [UserError!]!
  success: Boolean!
}

type UserError {
  field: String
  message: String!
  code: String
}

The mutation becomes:

createPost(input: CreatePostInput!): CreatePostPayload!

This design gives the client a structured place for operation-specific metadata.

However, payload types should not become a generic dumping ground for every possible server state. Keep them meaningful to the operation.

Another important design decision is whether expected business failures should be represented as normal structured data, GraphQL errors, or both. A consistent application-wide error strategy is more important than blindly choosing one pattern.

For example, invalid credentials might be an expected authentication failure, while an unexpected database outage is an exceptional server failure. Treating both identically can make client behavior and observability harder.

Mutation Response Patterns
Direct resource: createPost → Post
Simple operations can return the created or updated resource directly.
Payload object: createPost → CreatePostPayload
Useful when the operation needs structured metadata, warnings, errors, or related objects.
Structured user errors: field + message + code
Can help clients map expected validation failures to UI fields.
Key Takeaways
  • Mutation response design should match operation complexity.
  • Payload types can provide structured operation results.
  • Expected business errors and unexpected system failures should be distinguished.
  • A consistent error strategy improves client and server behavior.
Knowledge Check

When is a mutation payload type particularly useful?