Writing GraphQL Mutations
1. Defining Mutation Fields
| Convention | Detail |
|---|---|
| Naming | verbNoun: createPost, archiveOrder |
| Args | Single input object |
| Return | Payload type with mutated entity + errors |
| Sequential | Top-level mutation fields execute serially |
2. Using Mutation Arguments
Example: Single input arg
type Mutation {
updatePost(input: UpdatePostInput!): UpdatePostPayload!
}
input UpdatePostInput { id: ID!, title: String, body: String }
3. Returning Mutation Payload
| Field | Purpose |
|---|---|
| Mutated entity | post: Post |
| User errors | errors: [UserError!]! |
| Cursor / clientMutationId | Relay-style traceability |
| Side data | e.g. order: Order after canceling |
4. Creating Records
Example: Create mutation
Mutation: {
createPost: async (_, { input }, { db, user }) => {
if (!user) throw new GraphQLError("Unauthenticated");
const post = await db.post.create({ data: { ...input, authorId: user.id } });
return { post, errors: [] };
}
}
5. Updating Records
| Pattern | Detail |
|---|---|
| PATCH semantics | Omitted = unchanged, null = clear |
| Optimistic concurrency | Include version in input |
| Authorization | Verify ownership before update |
6. Deleting Records
Example: Delete returns id
type DeletePostPayload { deletedId: ID, errors: [UserError!]! }
type Mutation { deletePost(id: ID!): DeletePostPayload! }
7. Using Input Objects
| Reason | Benefit |
|---|---|
| Forward compatibility | Add fields without breaking signature |
| Reusability | Same input for create/upsert |
| Validation | Centralized via custom scalars/directives |
8. Returning Updated Data
Example: Return entity to update cache
mutation {
updatePost(input: { id: "1", title: "New" }) {
post { id title updatedAt }
errors { field message }
}
}
9. Handling Mutation Errors
| Error Kind | Strategy |
|---|---|
| Validation (field-level) | Return in errors array (typed) |
| Authorization | Throw GraphQLError with code |
| Not found | Throw with NOT_FOUND code |
| System failure | Throw; mask details via formatError |
10. Using Mutation Variables
Example: Mutation with variables
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
post { id }
errors { message }
}
}
11. Batching Mutations
| Approach | Detail |
|---|---|
| Multiple root fields (aliased) | Server runs serially |
| Single batch mutation | createPosts(inputs: [CreatePostInput!]!) |
| Transactional | Wrap server-side in DB transaction |