Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
27 Jul 2025 · 5 mnt baca ·Artikel 27 / 125
Go

27 Menulis Skema Mutation di GraphQL

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

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.

graphql
1mutation {
2  createUser(input: {name: "Budi", email: "budi@example.com"}) {
3    id
4    name
5    email
6  }
7}

2. Gunakan Input Object Types

Lebih baik gunakan input dibandingkan banyak argument langsung pada mutation, sehingga perubahan schema lebih terstruktur dan extendable.

graphql
1input CreateUserInput {
2  name: String!
3  email: String!
4}
5
6type Mutation {
7  createUser(input: CreateUserInput!): User
8}

3. Selalu Return Payload Object

Usahakan mutation selalu mengembalikan object payload, bukan hanya satu field.

graphql
1type CreateUserPayload {
2  user: User
3  errors: [Error!]
4}
5
6type Mutation {
7  createUser(input: CreateUserInput!): CreateUserPayload
8}

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.

graphql
1input BulkDeleteUserInput {
2  ids: [ID!]!
3}
4
5type Mutation {
6  bulkDeleteUser(input: BulkDeleteUserInput!): BulkDeletePayload
7}

6. Semi-Standardisasi Nama Mutation

Gunakan pola verbNoun, misal: createUser, updateProfile, deleteComment.

7. Masukkan Informasi Error dan Success States

Contoh payload:

graphql
 1type RegisterUserPayload {
 2  user: User
 3  success: Boolean!
 4  errors: [Error!]
 5}
 6
 7type Error {
 8  field: String
 9  message: String
10}

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.

graphql
1"""
2Mendaftarkan user baru dengan email dan nama.
3"""
4createUser(input: CreateUserInput!): CreateUserPayload

10. Gunakan Directive @deprecated

Jika ada mutation baru yang menggantikan yang lama, gunakan @deprecated.

graphql
1deletePostOld(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.

graphql
1input UpdateUserInput {
2  id: ID!
3  name: String
4  email: String
5}

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.

graphql
 1type Mutation {
 2  updateProfile(input: UpdateProfileInput!): UpdateProfilePayload
 3}
 4input UpdateProfileInput {
 5  clientMutationId: String
 6  ...
 7}
 8type UpdateProfilePayload {
 9  clientMutationId: String
10  ...
11}

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:

graphql
 1input UpdateProfileInput {
 2  id: ID!
 3  name: String
 4  email: String
 5  bio: String
 6}
 7type UpdateProfilePayload {
 8  user: User
 9  errors: [Error!]
10  success: Boolean!
11}
12type Mutation {
13  updateProfile(input: UpdateProfileInput!): UpdateProfilePayload
14}

Resolver (pseudocode Express.js/TypeScript):

typescript
 1const resolvers = {
 2  Mutation: {
 3    updateProfile: async (_, {input}, {db, user}) => {
 4      if (!user) return { success: false, errors: [{message: 'Unauthorized'}] };
 5
 6      const profile = await db.User.findById(input.id);
 7      if (!profile) return { success: false, errors: [{message: 'Not found'}] };
 8
 9      if (input.email && !isValidEmail(input.email)) {
10        return { success: false, errors: [{message: 'Invalid email'}] };
11      }
12
13      Object.assign(profile, input);
14
15      await profile.save();
16
17      return { user: profile, success: true, errors: [] };
18    }
19  }
20}

Query:

graphql
 1mutation {
 2  updateProfile(input: {
 3    id: "12", 
 4    name: "Budi Santoso", 
 5    email: "budi@contoh.com"
 6  }) {
 7    user {
 8      id
 9      name
10      email
11    }
12    success
13    errors {
14      message
15    }
16  }
17}

26. Tabel Perbandingan Schema: REST vs GraphQL Mutation

RESTGraphQL
Endpoint/users/{id}mutation {updateUser}
HTTP VerbPATCHCustom via schema
PayloadJSON bodyParam via input object
ResponseTergantung implementasiCustom payload, bisa error & data
ValidationManual, biasanya via middlewareSchema + custom resolver validation
AtomicityTergantung backendTergantung resolver
Versi/DependPerlu versioning APISkema backward compatible & deprecation

27. Diagram Alur Mutation GraphQL

MERMAID
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

Artikel Terkait

💬 Komentar