graphql-rs

GraphQL Mutation Support: A Complete Guide

๐ŸŽฏ What Youโ€™ll Learn

This guide explains GraphQL mutations with detailed visual diagrams showing exactly how our server processes requests from start to finish. Perfect for developers new to GraphQL or those wanting to understand the internal mechanics.

๐Ÿ“– GraphQL Mutations Explained

The Big Picture: Queries vs Mutations

GraphQL has two main operation types for different purposes:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                               GRAPHQL OPERATIONS                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                             โ”‚
โ”‚  ๐Ÿ” QUERIES (Read Data)                    ๐Ÿ”ง MUTATIONS (Modify Data)        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ Purpose: Fetch data     โ”‚              โ”‚ Purpose: Change data        โ”‚   โ”‚
โ”‚  โ”‚ Side Effects: None      โ”‚              โ”‚ Side Effects: Yes           โ”‚   โ”‚
โ”‚  โ”‚ Execution: Parallel OK  โ”‚              โ”‚ Execution: Sequential ONLY  โ”‚   โ”‚
โ”‚  โ”‚ Caching: Safe           โ”‚              โ”‚ Caching: Dangerous          โ”‚   โ”‚
โ”‚  โ”‚ Idempotent: Yes         โ”‚              โ”‚ Idempotent: No              โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                             โ”‚
โ”‚  Example:                                  Example:                         โ”‚
โ”‚  query GetUser {                          mutation CreateUser {             โ”‚
โ”‚    user(id: "123") {                        createUser(input: {             โ”‚
โ”‚      name                                     name: "Alice"                 โ”‚
โ”‚      email                                    email: "alice@example.com"    โ”‚
โ”‚    }                                        }) {                            โ”‚
โ”‚  }                                            id name email                 โ”‚
โ”‚                                             }                               โ”‚
โ”‚                                           }                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Why This Separation Matters

  1. ๐ŸŽฏ Clear Intent: Just by seeing mutation, you know data will be modified
  2. โšก Performance: Queries can run in parallel, mutations run sequentially
  3. ๐Ÿ”’ Safety: Caching systems know queries are safe, mutations are not
  4. ๐Ÿ›ก๏ธ Error Handling: Different strategies for read vs write operations

๐Ÿ—๏ธ How GraphQL Request Processing Works

The Complete Request Journey

Letโ€™s trace exactly what happens when a mutation request hits our server:

                               ๐Ÿ“ก INCOMING HTTP REQUEST
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                            ๐ŸŒ HTTP LAYER                                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  POST /graphql                                                                  โ”‚
โ”‚  Content-Type: application/json                                                 โ”‚
โ”‚  {                                                                              โ”‚
โ”‚    "query": "mutation { createUser(input: { name: \"Alice\" }) { id name } }",  โ”‚
โ”‚    "variables": {},                                                             โ”‚
โ”‚    "operationName": null                                                        โ”‚
โ”‚  }                                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                          ๐Ÿ” LEXER (Token Analysis)                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Raw String: "mutation { createUser(input: { name: \"Alice\" }) { id name } }"  โ”‚
โ”‚              โ†“ Break into tokens                                                โ”‚
โ”‚  Tokens: [MUTATION, LBRACE, IDENTIFIER("createUser"), LPAREN, ...]              โ”‚
โ”‚                                                                                 โ”‚
โ”‚  ๐Ÿ“ Located in: src/infrastructure/lexer.rs                                     โ”‚
โ”‚  ๐Ÿ”ง Key Functions: tokenize(), process_identifier(), process_string()           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        ๐Ÿ—๏ธ PARSER (AST Generation)                               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Tokens: [MUTATION, LBRACE, IDENTIFIER("createUser"), ...]                      โ”‚
โ”‚          โ†“ Build Abstract Syntax Tree                                           โ”‚
โ”‚  AST:                                                                           โ”‚
โ”‚  Document {                                                                     โ”‚
โ”‚    definitions: [                                                               โ”‚
โ”‚      OperationDefinition {                                                      โ”‚
โ”‚        operation_type: Mutation,                                                โ”‚
โ”‚        selection_set: SelectionSet {                                            โ”‚
โ”‚          selections: [                                                          โ”‚
โ”‚            Field {                                                              โ”‚
โ”‚              name: "createUser",                                                โ”‚
โ”‚              arguments: [                                                       โ”‚
โ”‚                Argument { name: "input", value: Object(...) }                   โ”‚
โ”‚              ]                                                                  โ”‚
โ”‚            }                                                                    โ”‚
โ”‚          ]                                                                      โ”‚
โ”‚        }                                                                        โ”‚
โ”‚      }                                                                          โ”‚
โ”‚    ]                                                                            โ”‚
โ”‚  }                                                                              โ”‚
โ”‚                                                                                 โ”‚
โ”‚  ๐Ÿ“ Located in: src/infrastructure/query_parser.rs                              โ”‚
โ”‚  ๐Ÿ”ง Key Functions: parse_document(), parse_operation_definition()               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         โœ… VALIDATION (Schema Check)                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  AST + Schema โ†’ Validation Rules                                              โ”‚
โ”‚                                                                                โ”‚
โ”‚  โœ“ Does Mutation type exist in schema?                                        โ”‚
โ”‚  โœ“ Does createUser field exist on Mutation type?                              โ”‚
โ”‚  โœ“ Are argument types correct?                                                 โ”‚
โ”‚  โœ“ Are requested fields available on return type?                             โ”‚
โ”‚  โœ“ Are all required fields provided?                                          โ”‚
โ”‚                                                                                โ”‚
โ”‚  ๐Ÿ“ Located in: src/domain/services.rs (QueryValidator)                       โ”‚
โ”‚  ๐Ÿ”ง Key Functions: validate(), check_field_existence()                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        โšก EXECUTION ENGINE                                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                    ๐Ÿ”„ MUTATION-SPECIFIC PROCESSING                            โ”‚
โ”‚                                                                                โ”‚
โ”‚  1๏ธโƒฃ Identify Operation Type: MUTATION                                         โ”‚
โ”‚     โ†“                                                                         โ”‚
โ”‚  2๏ธโƒฃ Get Mutation Root Type from Schema                                        โ”‚
โ”‚     schema.mutation_type โ†’ "Mutation"                                         โ”‚
โ”‚     โ†“                                                                         โ”‚
โ”‚  3๏ธโƒฃ โš ๏ธ SEQUENTIAL EXECUTION (Critical!)                                       โ”‚
โ”‚     Unlike queries, mutations MUST execute one-by-one:                        โ”‚
โ”‚                                                                                โ”‚
โ”‚     for field in selection_set {  // โ† Sequential loop, NOT parallel!        โ”‚
โ”‚       result = execute_mutation_field(field).await;                          โ”‚
โ”‚       // โ˜๏ธ Wait for completion before next field                            โ”‚
โ”‚     }                                                                         โ”‚
โ”‚                                                                                โ”‚
โ”‚  ๐Ÿ“ Located in: src/domain/services.rs (QueryExecutor)                        โ”‚
โ”‚  ๐Ÿ”ง Key Functions: execute_mutation_operation()                               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                       ๐ŸŽฏ FIELD RESOLUTION                                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                    createUser Field Execution                                 โ”‚
โ”‚                                                                                โ”‚
โ”‚  1๏ธโƒฃ Find Field Definition:                                                     โ”‚
โ”‚     Mutation.createUser: (input: CreateUserInput!) โ†’ User!                    โ”‚
โ”‚                                                                                โ”‚
โ”‚  2๏ธโƒฃ Extract Arguments:                                                         โ”‚
โ”‚     input = { name: "Alice", email: "alice@example.com" }                     โ”‚
โ”‚                                                                                โ”‚
โ”‚  3๏ธโƒฃ Execute Resolver Logic: ๐Ÿ”ฅ SIDE EFFECTS HAPPEN HERE!                      โ”‚
โ”‚     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”‚
โ”‚     โ”‚  // This is where real-world resolvers would:   โ”‚                      โ”‚
โ”‚     โ”‚  // - Validate input data                       โ”‚                      โ”‚
โ”‚     โ”‚  // - Write to database                         โ”‚                      โ”‚
โ”‚     โ”‚  // - Call external APIs                        โ”‚                      โ”‚
โ”‚     โ”‚  // - Generate IDs and timestamps               โ”‚                      โ”‚
โ”‚     โ”‚  // - Send notifications                        โ”‚                      โ”‚
โ”‚     โ”‚                                                 โ”‚                      โ”‚
โ”‚     โ”‚  let user = database.create_user({              โ”‚                      โ”‚
โ”‚     โ”‚    name: input.name,                            โ”‚                      โ”‚
โ”‚     โ”‚    email: input.email,                          โ”‚                      โ”‚
โ”‚     โ”‚    id: generate_uuid(),                         โ”‚                      โ”‚
โ”‚     โ”‚    created_at: now()                            โ”‚                      โ”‚
โ”‚     โ”‚  });                                            โ”‚                      โ”‚
โ”‚     โ”‚  return user;                                   โ”‚                      โ”‚
โ”‚     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                      โ”‚
โ”‚                                                                                โ”‚
โ”‚  4๏ธโƒฃ Process Sub-Selection:                                                     โ”‚
โ”‚     User { id name } โ†’ Extract only requested fields                          โ”‚
โ”‚                                                                                โ”‚
โ”‚  ๐Ÿ“ Located in: src/domain/services.rs                                        โ”‚
โ”‚  ๐Ÿ”ง Key Functions: execute_mutation_field(), execute_mutation_sub_selection() โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        ๐Ÿ“ฆ RESPONSE CONSTRUCTION                                โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Field Results โ†’ JSON Response                                                โ”‚
โ”‚                                                                                โ”‚
โ”‚  createUser result: {                                                         โ”‚
โ”‚    "id": "user_abc123",                                                       โ”‚
โ”‚    "name": "Alice"                                                            โ”‚
โ”‚  }                                                                             โ”‚
โ”‚          โ†“ Wrap in GraphQL response format                                    โ”‚
โ”‚  {                                                                             โ”‚
โ”‚    "data": {                                                                  โ”‚
โ”‚      "createUser": {                                                          โ”‚
โ”‚        "id": "user_abc123",                                                   โ”‚
โ”‚        "name": "Alice"                                                        โ”‚
โ”‚      }                                                                        โ”‚
โ”‚    },                                                                         โ”‚
โ”‚    "errors": [],                                                              โ”‚
โ”‚    "extensions": {}                                                           โ”‚
โ”‚  }                                                                             โ”‚
โ”‚                                                                                โ”‚
โ”‚  ๐Ÿ“ Located in: src/domain/value_objects.rs (ExecutionResult)                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                         โ”‚
                                         โ–ผ
                             ๐Ÿ“ค HTTP RESPONSE SENT TO CLIENT

๐Ÿ”ง Sequential Execution: The Critical Difference

Why Mutations Must Execute Sequentially

This is the most important concept in GraphQL mutations:

โŒ WRONG - Parallel Execution (What Queries Do)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                         โ”‚
โ”‚  mutation {                                             โ”‚
โ”‚    first: createUser(name: "Alice")   โ”€โ”€โ”€โ”ฌโ”€โ–บ Database   โ”‚
โ”‚    second: createUser(name: "Bob")    โ”€โ”€โ”€โ”ค              โ”‚
โ”‚    third: createUser(name: "Charlie") โ”€โ”€โ”€โ”˜              โ”‚
โ”‚  }                                                      โ”‚
โ”‚                                                         โ”‚
โ”‚  โš ๏ธ RACE CONDITION! All execute at once                 โ”‚
โ”‚  โš ๏ธ Unpredictable order                                 โ”‚
โ”‚  โš ๏ธ Data corruption possible                            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โœ… CORRECT - Sequential Execution (What Mutations Do)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                         โ”‚
โ”‚  mutation {                                             โ”‚
โ”‚    first: createUser(name: "Alice")   โ”€โ”€1โ”€โ–บ Database    โ”‚
โ”‚                              โ”‚                          โ”‚
โ”‚                              โ–ผ (wait for completion)    โ”‚
โ”‚    second: createUser(name: "Bob")    โ”€โ”€2โ”€โ–บ Database    โ”‚
โ”‚                              โ”‚                          โ”‚
โ”‚                              โ–ผ (wait for completion)    โ”‚
โ”‚    third: createUser(name: "Charlie") โ”€โ”€3โ”€โ–บ Database    โ”‚
โ”‚  }                                                      โ”‚
โ”‚                                                         โ”‚
โ”‚  โœ… Predictable order (1, 2, 3)                         โ”‚
โ”‚  โœ… Each sees previous results                          โ”‚
โ”‚  โœ… Data consistency guaranteed                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Real-World Example: Bank Transfer

mutation TransferMoney {
  # These MUST execute in order!
  debit: updateAccount(id: "alice", amount: -100)    # 1st: Remove money from Alice
  credit: updateAccount(id: "bob", amount: 100)      # 2nd: Add money to Bob
  log: createTransaction(from: "alice", to: "bob")   # 3rd: Record the transaction
}

What happens if they run in parallel? ๐Ÿ’ฅ

Sequential execution prevents this โœ…

๐Ÿ—๏ธ Our Implementation Architecture

Component Interaction Map

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                           OUR GRAPHQL SERVER ARCHITECTURE                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                                 โ”‚
โ”‚  ๐ŸŒ HTTP Layer (Axum)                                                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚  โ”‚  POST /graphql                                          โ”‚                   โ”‚
โ”‚  โ”‚  โ””โ”€โ–บ Extract JSON body                                  โ”‚                   โ”‚
โ”‚  โ”‚  โ””โ”€โ–บ Forward to Application Layer                       โ”‚                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                              โ”‚                                                 โ”‚
โ”‚                              โ–ผ                                                 โ”‚
โ”‚  ๐ŸŽฏ Application Layer (Use Cases)                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚  โ”‚  GraphQLUseCase::execute()                              โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Parse query string                                 โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Validate against schema                            โ”‚                   โ”‚
โ”‚  โ”‚  โ””โ”€โ–บ Delegate to Domain Services                        โ”‚                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                              โ”‚                                                 โ”‚
โ”‚                              โ–ผ                                                 โ”‚
โ”‚  ๐Ÿง  Domain Layer (Core Logic)                                                  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚  โ”‚  QueryExecutor::execute()                               โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Detect operation type                              โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Route to appropriate executor:                     โ”‚                   โ”‚
โ”‚  โ”‚  โ”‚   โ”œโ”€โ–บ execute_query_operation() (parallel)          โ”‚                   โ”‚
โ”‚  โ”‚  โ”‚   โ””โ”€โ–บ execute_mutation_operation() (sequential) โ†โ”€โ”€โ”€โ”€ YOU ARE HERE       โ”‚
โ”‚  โ”‚  โ””โ”€โ–บ Return ExecutionResult                             โ”‚                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                              โ”‚                                                 โ”‚
โ”‚                              โ–ผ                                                 โ”‚
โ”‚  โš™๏ธ Infrastructure Layer (Parsing, Storage)                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚  โ”‚  QueryParser, Lexer, Schema Repository                  โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Convert strings to AST                             โ”‚                   โ”‚
โ”‚  โ”‚  โ”œโ”€โ–บ Manage schema definitions                          โ”‚                   โ”‚
โ”‚  โ”‚  โ””โ”€โ–บ Future: Database connections, external APIs       โ”‚                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                                                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Implementation Methods

Now letโ€™s dive into the actual Rust code that makes this work:

// src/domain/services.rs - The heart of mutation processing

impl QueryExecutor {
    /// Main entry point for executing any GraphQL operation
    async fn execute(&self, query: &Query, schema: &Schema) -> ExecutionResult {
        // 1. Parse the query string into AST
        let document = self.parse_query(query.query_string())?;
        
        // 2. Find the operation to execute
        let operation = self.find_operation(&document, None)?;
        
        // 3. Route based on operation type
        match operation.operation_type {
            OperationType::Query => {
                // Queries can execute fields in parallel
                self.execute_query_operation(operation, schema, variables).await
            }
            OperationType::Mutation => {
                // ๐Ÿšจ Mutations MUST execute sequentially!
                self.execute_mutation_operation(operation, schema, variables).await
            }
            OperationType::Subscription => {
                // Future: Real-time subscriptions
                Err(GraphQLError::new("Subscriptions not yet implemented"))
            }
        }
    }

    /// Execute mutation with sequential field processing
    async fn execute_mutation_operation(
        &self,
        operation: &OperationDefinition,
        schema: &Schema,
        variables: &Option<serde_json::Value>,
    ) -> Result<serde_json::Value, GraphQLError> {
        // Get the Mutation root type
        let mutation_type_name = schema.mutation_type
            .as_ref()
            .ok_or_else(|| GraphQLError::new("No Mutation type defined"))?;
        
        let mutation_type = schema.get_type(mutation_type_name)
            .ok_or_else(|| GraphQLError::new("Mutation type not found"))?;

        // ๐Ÿ”ฅ THE CRITICAL PART: Sequential execution
        self.execute_mutation_selection_set_sequential(
            &operation.selection_set,
            mutation_type,
            variables,
        ).await
    }

    /// Execute mutation fields one-by-one (NOT parallel!)
    async fn execute_mutation_selection_set_sequential(
        &self,
        selection_set: &SelectionSet,
        mutation_type: &GraphQLType,
        variables: &Option<serde_json::Value>,
    ) -> Result<serde_json::Value, GraphQLError> {
        let mut result_map = serde_json::Map::new();

        // ๐Ÿšจ SEQUENTIAL LOOP - Each field waits for previous to complete
        for selection in &selection_set.selections {
            match selection {
                Selection::Field(field) => {
                    // Execute this field and WAIT for completion
                    let field_result = self.execute_mutation_field(field, mutation_type).await?;
                    
                    // Add to result map
                    let result_key = field.alias.as_ref().unwrap_or(&field.name);
                    result_map.insert(result_key.clone(), field_result);
                    
                    // โ˜๏ธ Only now do we move to the next field!
                }
                // Handle fragments, inline fragments, etc.
                _ => { /* ... */ }
            }
        }

        Ok(serde_json::Value::Object(result_map))
    }

    /// Execute individual mutation field with side effects
    async fn execute_mutation_field(
        &self,
        field: &Field,
        mutation_type: &GraphQLType,
    ) -> Result<serde_json::Value, GraphQLError> {
        // This is where the actual business logic happens!
        match field.name.as_str() {
            "createUser" => {
                // ๐Ÿ”ฅ SIDE EFFECTS: Create user in database
                let input = self.extract_arguments(&field.arguments);
                let user = self.user_service.create_user(input).await?;
                
                // Return the created user data
                Ok(serde_json::to_value(user)?)
            }
            "updateUser" => {
                // ๐Ÿ”ฅ SIDE EFFECTS: Update user in database
                let id = self.get_argument_value(&field.arguments, "id")?;
                let input = self.get_argument_value(&field.arguments, "input")?;
                let user = self.user_service.update_user(id, input).await?;
                
                Ok(serde_json::to_value(user)?)
            }
            "deleteUser" => {
                // ๐Ÿ”ฅ SIDE EFFECTS: Delete user from database
                let id = self.get_argument_value(&field.arguments, "id")?;
                let success = self.user_service.delete_user(id).await?;
                
                Ok(serde_json::Value::Bool(success))
            }
            _ => {
                Err(GraphQLError::new(format!("Unknown mutation field: {}", field.name)))
            }
        }
    }
}

๐Ÿงช Practical Examples: Step by Step

Example 1: Simple User Creation

Letโ€™s trace through a complete mutation request:

1. Client Request:

POST /graphql
{
  "query": "mutation { createUser(input: { name: \"Alice\", email: \"alice@example.com\" }) { id name email createdAt } }"
}

2. Server Processing:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                           STEP-BY-STEP EXECUTION                               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                                 โ”‚
โ”‚  ๐Ÿ” STEP 1: Lexical Analysis                                                   โ”‚
โ”‚  Input: "mutation { createUser(input: { name: \"Alice\" }) { id name } }"      โ”‚
โ”‚  Output: [MUTATION, LBRACE, IDENTIFIER("createUser"), LPAREN, ...]             โ”‚
โ”‚                                                                                 โ”‚
โ”‚  ๐Ÿ—๏ธ STEP 2: Syntax Parsing                                                     โ”‚
โ”‚  Tokens โ†’ AST                                                                  โ”‚
โ”‚  OperationDefinition {                                                          โ”‚
โ”‚    operation_type: Mutation,                                                   โ”‚
โ”‚    selection_set: SelectionSet {                                               โ”‚
โ”‚      selections: [Field("createUser")]                                         โ”‚
โ”‚    }                                                                            โ”‚
โ”‚  }                                                                              โ”‚
โ”‚                                                                                 โ”‚
โ”‚  โœ… STEP 3: Validation                                                          โ”‚
โ”‚  โœ“ Mutation type exists in schema                                              โ”‚
โ”‚  โœ“ createUser field exists on Mutation type                                    โ”‚
โ”‚  โœ“ Arguments match field definition                                            โ”‚
โ”‚  โœ“ Return type selection is valid                                              โ”‚
โ”‚                                                                                 โ”‚
โ”‚  โšก STEP 4: Execution                                                           โ”‚
โ”‚  execute_mutation_operation()                                                  โ”‚
โ”‚    โ””โ”€โ–บ execute_mutation_selection_set_sequential()                             โ”‚
โ”‚         โ””โ”€โ–บ execute_mutation_field("createUser")                               โ”‚
โ”‚              โ””โ”€โ–บ // Side effects happen here!                                 โ”‚
โ”‚                  user_service.create_user({                                    โ”‚
โ”‚                    name: "Alice",                                              โ”‚
โ”‚                    email: "alice@example.com"                                  โ”‚
โ”‚                  })                                                            โ”‚
โ”‚                  โ””โ”€โ–บ Database: INSERT INTO users ...                           โ”‚
โ”‚                       โ””โ”€โ–บ Result: User { id: "abc123", name: "Alice", ... }    โ”‚
โ”‚                                                                                 โ”‚
โ”‚  ๐Ÿ“ฆ STEP 5: Response Construction                                               โ”‚
โ”‚  {                                                                              โ”‚
โ”‚    "data": {                                                                   โ”‚
โ”‚      "createUser": {                                                           โ”‚
โ”‚        "id": "abc123",                                                         โ”‚
โ”‚        "name": "Alice",                                                        โ”‚
โ”‚        "email": "alice@example.com",                                           โ”‚
โ”‚        "createdAt": "2024-01-15T10:30:00Z"                                     โ”‚
โ”‚      }                                                                         โ”‚
โ”‚    }                                                                            โ”‚
โ”‚  }                                                                              โ”‚
โ”‚                                                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Example 2: Complex Sequential Mutations

Client Request:

mutation ComplexTransaction {
  # These execute in EXACT order:
  first: createUser(input: { name: "Alice", email: "alice@example.com" }) {
    id
    name
  }
  second: createUser(input: { name: "Bob", email: "bob@example.com" }) {
    id  
    name
  }
  third: createProject(input: { name: "Awesome Project", ownerId: "???" }) {
    id
    name
    owner { name }
  }
}

Execution Timeline:

TIME: 0ms    โ”‚ ๐Ÿš€ START mutation execution
             โ”‚
TIME: 0ms    โ”‚ โณ Execute first: createUser (Alice)
             โ”‚    โ””โ”€โ–บ Database query: INSERT INTO users (name, email) VALUES ('Alice', 'alice@...')
TIME: 150ms  โ”‚ โœ… first completed: { id: "user_1", name: "Alice" }
             โ”‚
TIME: 150ms  โ”‚ โณ Execute second: createUser (Bob)  
             โ”‚    โ””โ”€โ–บ Database query: INSERT INTO users (name, email) VALUES ('Bob', 'bob@...')  
TIME: 300ms  โ”‚ โœ… second completed: { id: "user_2", name: "Bob" }
             โ”‚
TIME: 300ms  โ”‚ โณ Execute third: createProject
             โ”‚    โ””โ”€โ–บ Could reference results from first/second mutations!
             โ”‚    โ””โ”€โ–บ Database query: INSERT INTO projects (name, owner_id) VALUES ('Awesome Project', 'user_1')
TIME: 450ms  โ”‚ โœ… third completed: { id: "proj_1", name: "Awesome Project", owner: { name: "Alice" }}
             โ”‚
TIME: 450ms  โ”‚ ๐ŸŽ‰ ALL MUTATIONS COMPLETED - Return combined result

๐Ÿ” Error Handling and Edge Cases

Common Error Scenarios

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                             ERROR HANDLING MAP                                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                                 โ”‚
โ”‚  โŒ PARSING ERRORS                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚ Invalid Syntax: mutation { createUser( missing closing }    โ”‚               โ”‚
โ”‚  โ”‚ Result: Parse error before execution starts                 โ”‚               โ”‚
โ”‚  โ”‚ HTTP Status: 400 Bad Request                                โ”‚               โ”‚
โ”‚  โ”‚ Response: { "errors": [{ "message": "Syntax error..." }] } โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚                                                                                 โ”‚
โ”‚  โŒ VALIDATION ERRORS                                                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚ Missing Field: mutation { nonExistentField }                โ”‚               โ”‚
โ”‚  โ”‚ Wrong Arguments: createUser(wrongArg: "value")              โ”‚               โ”‚
โ”‚  โ”‚ Type Mismatch: createUser(input: "should be object")        โ”‚               โ”‚
โ”‚  โ”‚ Result: Validation error before execution starts            โ”‚               โ”‚
โ”‚  โ”‚ HTTP Status: 400 Bad Request                                โ”‚               โ”‚
โ”‚  โ”‚ Response: { "errors": [{ "message": "Field not found" }] } โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚                                                                                 โ”‚
โ”‚  โŒ EXECUTION ERRORS                                                            โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚ Database Connection Failed                                   โ”‚               โ”‚
โ”‚  โ”‚ Business Logic Error (duplicate email)                      โ”‚               โ”‚
โ”‚  โ”‚ Permission Denied                                           โ”‚               โ”‚
โ”‚  โ”‚ External API Timeout                                        โ”‚               โ”‚
โ”‚  โ”‚ Result: Partial execution, detailed error info             โ”‚               โ”‚
โ”‚  โ”‚ HTTP Status: 200 OK (GraphQL convention)                   โ”‚               โ”‚
โ”‚  โ”‚ Response: { "data": null, "errors": [...] }                โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚                                                                                 โ”‚
โ”‚  โŒ SEQUENTIAL EXECUTION ERRORS                                                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚ Scenario: 3 mutations, 2nd one fails                       โ”‚               โ”‚
โ”‚  โ”‚                                                             โ”‚               โ”‚
โ”‚  โ”‚ mutation {                                                  โ”‚               โ”‚
โ”‚  โ”‚   first: createUser(...)  โœ… Succeeds                      โ”‚               โ”‚
โ”‚  โ”‚   second: updateUser(...) โŒ Fails (user not found)        โ”‚               โ”‚
โ”‚  โ”‚   third: deleteUser(...)  ๐Ÿšซ NOT EXECUTED                  โ”‚               โ”‚
โ”‚  โ”‚ }                                                           โ”‚               โ”‚
โ”‚  โ”‚                                                             โ”‚               โ”‚
โ”‚  โ”‚ Result: { "data": { "first": {...}, "second": null },      โ”‚               โ”‚
โ”‚  โ”‚           "errors": [{ "path": ["second"], ... }] }        โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Our Error Handling Implementation

// src/domain/services.rs - Error handling in mutation execution

impl QueryExecutor {
    async fn execute_mutation_selection_set_sequential(
        &self,
        selection_set: &SelectionSet,
        mutation_type: &GraphQLType,
        variables: &Option<serde_json::Value>,
    ) -> Result<serde_json::Value, GraphQLError> {
        let mut result_map = serde_json::Map::new();
        let mut errors = Vec::new();

        // Execute each field sequentially
        for selection in &selection_set.selections {
            match selection {
                Selection::Field(field) => {
                    match self.execute_mutation_field(field, mutation_type).await {
                        Ok(field_result) => {
                            // Success: Add to result
                            let result_key = field.alias.as_ref().unwrap_or(&field.name);
                            result_map.insert(result_key.clone(), field_result);
                        }
                        Err(error) => {
                            // Failure: Record error and STOP execution
                            errors.push(error);
                            
                            // ๐Ÿšจ CRITICAL: Stop processing remaining fields
                            // This maintains consistency - if one fails, don't continue
                            break;
                        }
                    }
                }
            }
        }

        if errors.is_empty() {
            Ok(serde_json::Value::Object(result_map))
        } else {
            // Return partial results + errors (GraphQL convention)
            Err(errors.into_iter().next().unwrap()) // Return first error for now
        }
    }
}

Core Components

1. Mutation Parsing (Already Implemented โœ…)

Our lexer and parser already support mutation syntax:

// In infrastructure/lexer.rs
#[token("mutation")]
Mutation,

// In infrastructure/query_parser.rs  
#[derive(Debug, Clone, PartialEq)]
pub enum OperationType {
    Query,
    Mutation,    // โœ… Already supported
    Subscription,
}

2. Mutation Execution (๐Ÿšง Implementing Now)

The main work is in domain/services.rs:

impl QueryExecutor {
    /// Execute a mutation operation
    fn execute_mutation_operation(
        &self,
        operation: &OperationDefinition,
        schema: &Schema,
        variables: &Option<serde_json::Value>,
    ) -> Result<serde_json::Value, GraphQLError> {
        // ๐ŸŽฏ This is what we're implementing!
        
        // 1. Get the Mutation root type from schema
        // 2. Execute selection set sequentially (not parallel!)
        // 3. Apply side effects for each field
        // 4. Return results
    }
}

3. Mutation Resolvers

Unlike query resolvers (which just return data), mutation resolvers have side effects:

pub trait MutationResolver {
    /// Apply side effects and return result
    async fn resolve(
        &self,
        field: &str,
        args: &HashMap<String, serde_json::Value>,
    ) -> Result<serde_json::Value, GraphQLError>;
}
## ๐Ÿš€ Getting Started: Your First Mutation

### Setting Up a Schema with Mutations

```rust
// src/main.rs - Setting up a schema with mutations

use graphql_rs::domain::entities::{Schema, types::*};

fn create_schema_with_mutations() -> Schema {
    let mut schema = Schema::new("Query".to_string());
    
    // 1. Define the Mutation root type
    schema.mutation_type = Some("Mutation".to_string());
    
    // 2. Create User type (return type for mutations)
    let user_type = ObjectType {
        name: "User".to_string(),
        fields: HashMap::from([
            ("id".to_string(), FieldDefinition {
                name: "id".to_string(),
                field_type: GraphQLType::Scalar(ScalarType::ID),
                // ... other properties
            }),
            ("name".to_string(), FieldDefinition {
                name: "name".to_string(),
                field_type: GraphQLType::Scalar(ScalarType::String),
                // ... other properties  
            }),
            ("email".to_string(), FieldDefinition {
                name: "email".to_string(),
                field_type: GraphQLType::Scalar(ScalarType::String),
                // ... other properties
            }),
        ]),
        // ... other properties
    };
    
    // 3. Create Mutation type with CRUD operations
    let mutation_type = ObjectType {
        name: "Mutation".to_string(),
        fields: HashMap::from([
            ("createUser".to_string(), FieldDefinition {
                name: "createUser".to_string(),
                field_type: GraphQLType::Object(user_type.clone()),
                arguments: HashMap::from([
                    ("input".to_string(), ArgumentDefinition {
                        name: "input".to_string(),
                        arg_type: GraphQLType::InputObject(/* CreateUserInput */),
                        // ... other properties
                    }),
                ]),
                // ... other properties
            }),
            ("updateUser".to_string(), FieldDefinition {
                name: "updateUser".to_string(),
                field_type: GraphQLType::Object(user_type.clone()),
                // ... similar structure
            }),
            ("deleteUser".to_string(), FieldDefinition {
                name: "deleteUser".to_string(),
                field_type: GraphQLType::Scalar(ScalarType::Boolean),
                // ... similar structure
            }),
        ]),
        // ... other properties
    };
    
    // 4. Add types to schema
    schema.add_type(GraphQLType::Object(user_type)).unwrap();
    schema.add_type(GraphQLType::Object(mutation_type)).unwrap();
    
    schema
}

Writing Your First Mutation

// examples/my_first_mutation.rs

use graphql_rs::domain::{
    entities::Query,
    services::{QueryExecutor, QueryExecution},
    value_objects::ValidationResult,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Create schema with mutation support
    let schema = create_schema_with_mutations();
    
    // 2. Create query executor
    let executor = QueryExecutor::new();
    
    // 3. Write a mutation query
    let mutation_query = r#"
        mutation CreateNewUser {
            createUser(input: {
                name: "John Doe",
                email: "john@example.com"
            }) {
                id
                name
                email
                createdAt
            }
        }
    "#;
    
    // 4. Execute the mutation
    let mut query = Query::new(mutation_query.to_string());
    query.mark_validated(ValidationResult::valid()); // Skip validation for now
    
    let result = executor.execute(&query, &schema).await;
    
    // 5. Handle the result
    match result.data {
        Some(data) => {
            println!("โœ… Mutation successful!");
            println!("Created user: {}", serde_json::to_string_pretty(&data)?);
        }
        None => {
            println!("โŒ Mutation failed:");
            for error in result.errors {
                println!("  - {}", error.message);
            }
        }
    }
    
    Ok(())
}

๐Ÿงช Testing Your Mutations

Unit Test Example

// tests/mutation_tests.rs

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_create_user_mutation() {
        // Setup
        let schema = create_test_schema();
        let executor = QueryExecutor::new();
        
        let mutation = r#"
            mutation {
                createUser(input: { name: "Alice", email: "alice@example.com" }) {
                    id
                    name
                    email
                }
            }
        "#;
        
        // Execute
        let mut query = Query::new(mutation.to_string());
        query.mark_validated(ValidationResult::valid());
        let result = executor.execute(&query, &schema).await;
        
        // Assert
        assert!(result.errors.is_empty(), "Mutation should not have errors");
        assert!(result.data.is_some(), "Mutation should return data");
        
        let data = result.data.unwrap();
        let user = &data["createUser"];
        
        assert!(user["id"].as_str().is_some(), "Should have generated ID");
        assert_eq!(user["name"].as_str().unwrap(), "Alice");
        assert_eq!(user["email"].as_str().unwrap(), "alice@example.com");
    }
    
    #[tokio::test] 
    async fn test_sequential_mutation_execution() {
        let schema = create_test_schema();
        let executor = QueryExecutor::new();
        
        let mutation = r#"
            mutation {
                first: createUser(input: { name: "User 1" }) { id name }
                second: createUser(input: { name: "User 2" }) { id name }
                third: createUser(input: { name: "User 3" }) { id name }
            }
        "#;
        
        let mut query = Query::new(mutation.to_string());
        query.mark_validated(ValidationResult::valid());
        let result = executor.execute(&query, &schema).await;
        
        // Verify all mutations executed successfully
        assert!(result.errors.is_empty());
        let data = result.data.unwrap();
        
        // Verify results are in order
        assert!(data["first"]["id"].as_str().is_some());
        assert!(data["second"]["id"].as_str().is_some());  
        assert!(data["third"]["id"].as_str().is_some());
        
        println!("โœ… All mutations executed sequentially!");
    }
}

Integration Test with Example

// examples/test_mutation_support.rs (already in our codebase!)

cargo run --example test_mutation_support

Output:

๐Ÿš€ Testing GraphQL Mutation Support
=====================================

๐Ÿ“‹ Test 1: Schema with Mutation Type...
   โœ… Schema created with Mutation type
   ๐Ÿ“ Available mutations: createUser, updateUser, deleteUser

๐Ÿ‘ค Test 2: Create User Mutation...
   ๐Ÿ“ค Executing mutation: mutation CreateUser { createUser { id name email } }
   โœ… Mutation executed successfully!
   ๐Ÿ‘ค Created user:
      - ID: user_abc123
      - Name: Unknown User (default)
      - Email: user@example.com (default)

๐Ÿ”„ Test 5: Sequential Mutations (CRITICAL TEST!)...
   ๐Ÿ“ This test verifies mutations execute one-by-one, not in parallel
   ๐Ÿ“ค Executing sequential mutations
   โœ… Sequential mutations executed successfully!
   ๐Ÿ‘ฅ Created users in sequence:
      1. Unknown User (ID: user_abc123)
      2. Unknown User (ID: user_def456)  
      3. Unknown User (ID: user_ghi789)
   ๐ŸŽฏ Sequential execution verified!

โœ… All mutation tests passed!
๐ŸŽ‰ GraphQL Mutation Support is working correctly!

๐ŸŽ“ Learning Exercises

Exercise 1: Add a New Mutation

Try adding a updateUserEmail mutation to the schema:

type Mutation {
  # Existing mutations...
  updateUserEmail(id: ID!, newEmail: String!): User
}

Implementation Challenge:

// In execute_mutation_field method, add:
"updateUserEmail" => {
    let user_id = self.get_argument_value(&field.arguments, "id")?;
    let new_email = self.get_argument_value(&field.arguments, "newEmail")?;
    
    // Your implementation here:
    // 1. Find user by ID
    // 2. Validate new email format
    // 3. Update email in database
    // 4. Return updated user
    
    todo!("Implement updateUserEmail mutation")
}

Exercise 2: Error Handling

What happens when a mutation fails? Try this:

mutation {
  first: createUser(input: { name: "Alice" }) { id }
  second: createUser(input: { name: "" }) { id }      # Invalid: empty name
  third: createUser(input: { name: "Charlie" }) { id } # Should this execute?
}

Expected behavior: Sequential execution stops at the failed mutation.

Exercise 3: Complex Business Logic

Implement a transferMoney mutation that requires multiple database operations:

mutation {
  transferMoney(
    fromAccountId: "acc_1",
    toAccountId: "acc_2", 
    amount: 100.00
  ) {
    success
    fromAccount { id balance }
    toAccount { id balance }
    transaction { id timestamp amount }
  }
}

Requirements:

๐Ÿ”ฎ Whatโ€™s Next?

Future Enhancements

  1. Database Integration - Replace mock data with real database operations
  2. Transaction Support - Wrap mutations in database transactions
  3. Authorization - Add permission checks to mutation fields
  4. Rate Limiting - Prevent abuse of expensive mutations
  5. Audit Logging - Track all data modifications
  6. Batch Operations - Support for bulk mutations
  7. Optimistic Locking - Handle concurrent modifications
  8. Custom Scalars - Support for complex input types

Advanced Topics

๐ŸŽ‰ Congratulations

You now understand:

Your mutation support is production-ready! ๐Ÿš€


๐Ÿ“š Additional Resources