27 Menulis Skema Mutation di GraphQL
Sejak GraphQL menjadi primadona dalam arsitektur API, berbagai istilah seperti query, mutation, dan subscription mulai akrab di telinga developer. Sementara query digunakan untuk membaca data, mutation adalah elemen krusial untuk menulis atau memodifikasi data (insert, update, delete). Menulis skema mutation yang baik tidak sekadar mengikuti sintaks, tapi juga mengutamakan robust-ness, kemudahan scaling, dan maintainability.
Artikel ini berisi 27 tips praktis (best practice) menulis skema mutation di GraphQL, lengkap dengan contoh kode, simulasi, dan diagram alur yang bisa diterapkan di codebase Anda hari ini juga.
1. Pahami Fungsi Mutation
Mutation digunakan untuk semua operasi write pada data. Secara default, response dari mutation GraphQL adalah data terakhir setelah perubahan—unik dibanding REST.
mutation {
createUser(input: {name: "Budi", email: "budi@example.com"}) {
id
name
email
}
}
2. Gunakan Input Object Types
Lebih baik gunakan input
dibandingkan banyak argument langsung pada mutation, sehingga perubahan schema lebih terstruktur dan extendable.
input CreateUserInput {
name: String!
email: String!
}
type Mutation {
createUser(input: CreateUserInput!): User
}
3. Selalu Return Payload Object
Usahakan mutation selalu mengembalikan object payload, bukan hanya satu field.
type CreateUserPayload {
user: User
errors: [Error!]
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload
}
4. Return Data yang Sudah Diubah
Return-lah resource yang memang berubah agar frontend mudah melakukan cache update tanpa query kedua.
5. Dukung Bulk Operation (Batching)
Sediakan endpoint untuk batch create, update, dan delete untuk operasional skala besar.
input BulkDeleteUserInput {
ids: [ID!]!
}
type Mutation {
bulkDeleteUser(input: BulkDeleteUserInput!): BulkDeletePayload
}
6. Semi-Standardisasi Nama Mutation
Gunakan pola verbNoun
, misal: createUser
, updateProfile
, deleteComment
.
7. Masukkan Informasi Error dan Success States
Contoh payload:
type RegisterUserPayload {
user: User
success: Boolean!
errors: [Error!]
}
type Error {
field: String
message: String
}
8. Implementasikan Enumeration untuk State Tertentu
Hindari magic string. Gunakan enum untuk status, misal UserStatus
.
9. Dokumentasikan Skema Mutation
Selalu tambahkan docstring pada setiap input dan type. Ini membantu tim dan tools documentation.
"""
Mendaftarkan user baru dengan email dan nama.
"""
createUser(input: CreateUserInput!): CreateUserPayload
10. Gunakan Directive @deprecated
Jika ada mutation baru yang menggantikan yang lama, gunakan @deprecated
.
deletePostOld(input: DeletePostInput!): DeletePostPayload @deprecated(reason: "Use deletePost instead")
11. Optimalkan Partial Update dengan Input Nullable
Untuk update, gunakan input nullable agar bisa partial update, mirip PATCH di REST.
input UpdateUserInput {
id: ID!
name: String
email: String
}
12. Transaksi Atomic
Di backend resolver, pastikan mutation berjalan atomic (misal dengan database transaction).
13. Chained Mutation (Relay-style)
Setiap mutation bisa mengembalikan clientMutationId agar client bisa track response dan urutan operation.
type Mutation {
updateProfile(input: UpdateProfileInput!): UpdateProfilePayload
}
input UpdateProfileInput {
clientMutationId: String
...
}
type UpdateProfilePayload {
clientMutationId: String
...
}
14. Respon Kondisional
Support field di payload untuk memberikan status keberhasilan atau error spesifik.
15. Validasi Input di Resolver
Selalu lakukan input validation di layer resolver, walaupun sudah ada GraphQL validation di level schema.
16. Use-case Driven Mutation Granularity
Jangan terlalu granuler atau terlalu besar. Misal, update satu profile field saja? Atau sekalian update semua field sekalian? Sesuaikan dengan use-case frontend.
17. Protected Action (Authentication dan Authorization)
Mutation harus aman, implementasikan guard/middleware sesuai kebutuhan.
18. Jangan Gunakan Mutation untuk Query-only
Mutation sebaiknya tidak untuk operasi read saja.
19. Exposed Field Secara Selektif
Jangan expose semua field, misal field password hash tetap hidden.
20. Idempotency
Desain mutation agar idempotent, apalagi untuk sensitive operation (transfer uang, dll).
21. Error Mapping yang Konsisten
Error harus punya pola response yang sama di seluruh mutation.
22. Test Mutation Terus-menerus
Mutasi = write = rawan bug. Unit/integration test wajib.
23. Buat Enum MutationStatus Jika Dibutuhkan
Response mutation bisa punya enum: SUCCESS, FAILED, DUPLICATE, dsb.
24. Beri Tahu Client Saat Ada Side-effect
Contoh: user perlu verifikasi email, info-kan di payload.
25. Simulasi: Update User Profile
Mari simulasikan:
Skema:
input UpdateProfileInput {
id: ID!
name: String
email: String
bio: String
}
type UpdateProfilePayload {
user: User
errors: [Error!]
success: Boolean!
}
type Mutation {
updateProfile(input: UpdateProfileInput!): UpdateProfilePayload
}
Resolver (pseudocode Express.js/TypeScript):
const resolvers = {
Mutation: {
updateProfile: async (_, {input}, {db, user}) => {
if (!user) return { success: false, errors: [{message: 'Unauthorized'}] };
const profile = await db.User.findById(input.id);
if (!profile) return { success: false, errors: [{message: 'Not found'}] };
if (input.email && !isValidEmail(input.email)) {
return { success: false, errors: [{message: 'Invalid email'}] };
}
Object.assign(profile, input);
await profile.save();
return { user: profile, success: true, errors: [] };
}
}
}
Query:
mutation {
updateProfile(input: {
id: "12",
name: "Budi Santoso",
email: "budi@contoh.com"
}) {
user {
id
name
email
}
success
errors {
message
}
}
}
26. Tabel Perbandingan Schema: REST vs GraphQL Mutation
REST | GraphQL | |
---|---|---|
Endpoint | /users/{id} | mutation {updateUser} |
HTTP Verb | PATCH | Custom via schema |
Payload | JSON body | Param via input object |
Response | Tergantung implementasi | Custom payload, bisa error & data |
Validation | Manual, biasanya via middleware | Schema + custom resolver validation |
Atomicity | Tergantung backend | Tergantung resolver |
Versi/Depend | Perlu versioning API | Skema backward compatible & deprecation |
27. Diagram Alur Mutation GraphQL
flowchart TD A[Client] -->|Send Mutation Payload| B[GraphQL Server] B --> C{Validation} C -- valid --> D[Trigger Resolver] D --> E[DB Transaction] E --> F[Updated Data] F --> G[Return Payload (User, Errors, Success, etc)] C -- invalid --> H[Return Error Payload]
Kesimpulan
Menulis 27 skema mutation terbaik di GraphQL bukan hanya soal sintaks, melainkan memadukan aspek fungsional, keamanan, kemudahan maintain, serta scalability. Jadikanlah mutation di API Anda sebagai kontrak yang jelas antara client <> server, dan jangan ragu refactor untuk adaptasi kebutuhan baru.
Selamat bereksplorasi dengan mutation GraphQL—karena data yang berubah, membawa aplikasi bertumbuh! 🚀
Referensi
49 Serialisasi dan Deserialisasi Manual
Artikel Terhangat
30 Validasi Input di Mutation graphql-go
07 Jul 2025
51. Menggunakan TLS di gRPC Server
07 Jul 2025
50 Protobuf JSON Marshal dan Unmarshal
07 Jul 2025
27 Menulis Skema Mutation di GraphQL
07 Jul 2025
49 Serialisasi dan Deserialisasi Manual
07 Jul 2025

30 Validasi Input di Mutation graphql-go

51. Menggunakan TLS di gRPC Server

50 Protobuf JSON Marshal dan Unmarshal

27 Menulis Skema Mutation di GraphQL
