tutorial

108 Menangani Resolver Otomatis dan Manual

108 Menangani Resolver Otomatis dan Manual: Panduan Lengkap untuk Engineer

Resolver adalah komponen penting dalam banyak sistem perangkat lunak modern, mulai dari pengelolaan dependensi pada framework web, hingga penguraian query kompleks pada GraphQL. Namun, sering kali kita terjebak dengan dua jalur utama saat membangun resolver: secara otomatis atau manual. Menentukan kapan dan bagaimana menggunakan masing-masing pendekatan adalah seni — dan sains — tersendiri.

Pada artikel ini, saya akan membahas 108 cara (atau setidaknya mengupas hingga radiks detailnya!) untuk menangani resolver otomatis dan manual, termasuk mindset, pola desain, contoh kode, simulasi, hingga tips praktis dalam pengembangan produksi.


Mengenal Resolver

Secara umum, resolver adalah fungsi atau logika yang bertanggung jawab untuk mencari, mengambil, dan menyusun data akhir yang diminta oleh client. Dalam konteks modern, Anda bisa menemukannya dalam:

  • ORM (Object-Relational Mapping), seperti Sequelize atau Prisma
  • Framework API (Express.js, NestJS, Laravel, dsb)
  • GraphQL API layer

Misalnya, dalam GraphQL:

const resolvers = {
  Query: {
    user: (_, { id }, { db }) => db.users.findById(id)
  }
}

Resolver di atas mencari user berdasarkan id dari context database.


Resolver Otomatis vs. Manual: Definisi Singkat

PendekatanResolver OtomatisResolver Manual
DefinisiResolver dibuat secara otomatis oleh sistemResolver ditulis sendiri oleh developer
ContohORM auto-mapping, GraphQL codegenCustom function, query terpersonalisasi
KelebihanSedikit boilerplate, cepat, konsistenFleksibel, dapat dioptimasi spesifik kebutuhan
KekuranganKurangnya kontrol, kadang overfetching/underfetchingLebih banyak kode, rawan bug, maintenance berat
Kasus IdealCRUD standar, schema sederhanaLogic bisnis kompleks, query dinamis

Proses Kerja Resolver Otomatis

Bayangkan Anda membangun REST API dengan ORM seperti Sequelize, atau GraphQL dengan Prisma. ORM tersebut menyediakan resolver otomatis yang mengkonversi mapping tabel ke endpoint/field API.

Diagram alurnya kira-kira seperti berikut:

flowchart TD
    A[Client Request Field] --> B[Endpoint/Query Received]
    B --> C[Schema/Syntax Analyzer]
    C -- auto map --> D[ORM/Database Layer]
    D --> E[Auto-generated Resolver]
    E --> F[Fetch/Transform Data]
    F --> G[Return Response]

Proses ini memotong banyak waktu pengembangan dengan menghilangkan kebutuhan menulis resolver satu per satu.

Contoh Otomatisasi dengan Prisma (TypeScript + GraphQL)

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

const resolvers = {
  Query: {
    users: () => prisma.user.findMany(), // Prisma generate auto-mapping
    posts: () => prisma.post.findMany(),
  }
}

Prisma melakukan query secara otomatis, Anda hanya memanggil fungsi findMany().


Manual Resolver: Ketika Otomatisasi Tak Cukup

Ada kasus-kasus ketika otomatisasi resolver kurang fleksibel. Misalnya:

  • Anda perlu relational join yang sangat custom
  • Butuh logic bisnis ekstra pada proses fetching
  • Perlu validasi, transformasi, atau logging khusus

Contoh Resolver Manual pada GraphQL:

const resolvers = {
  Query: {
    userProfile: async (_, { userId }, { db }) => {
      const user = await db.users.findById(userId);
      if (!user) throw new Error("User not found");
      // Logic bisnis ekstra: track access
      await db.audit.logAccess(userId, 'profile_view');
      return {
        ...user,
        isPremium: user.subscription.status === "active",
        // transformasi lain
      }
    }
  }
}

Di sini, kita sepenuhnya mengendalikan bagaimana data user diambil, diproses, dan dikirimkan ke client, juga dapat menambah validasi dan audit.


Kapan Menggunakan Otomatis, Kapan Manual?

Berikut adalah pertimbangan, yang saya sarikan pada tabel berikut:

SkenarioOtomatisManual
CRUD Sederhana✔️
Optimisasi query (select field)✔️
Transformasi data kompleks✔️
Logika bisnis unik✔️
Cepat setup MVP✔️
Skema dinamis/berkembang✔️
Audit, Logging, Validasi✔️

Simulasi: Perbandingan Kinerja

Untuk studi kasus, asumsikan kita ingin mengambil data user dan order mereka. Menggunakan resolver otomatis (misal dengan ORM) dan resolver manual.

Benchmark: Resolver Otomatis

const resolvers = {
  Query: {
    usersWithOrders: (_, __, { db }) =>
      db.user.findMany({
        include: { orders: true }
      })
  }
}

Waktu rata-rata query: 50 ms
Kode: 3 baris

Benchmark: Resolver Manual

const resolvers = {
  Query: {
    usersWithOrders: async (_, __, { db }) => {
      const users = await db.user.findMany();
      return Promise.all(users.map(async (user) => ({
        ...user,
        orders: await db.order.findMany({ where: { userId: user.id } })
      })));
    }
  }
}

Waktu rata-rata query: 120 ms
Kode: 8 baris, lebih fleksibel (bisa tambah logic bisnis per user)

Insights

  • Otomatis cepat, tapi tidak bisa filter/transform per user.
  • Manual lambat (N+1 problem), namun bisa custom.

Solusi? Menggunakan DataLoader atau query batched di resolver manual agar performa tetap optimal.


Kombinasi: Hybrid Resolver

Kombinasikan keduanya untuk efisiensi dan fleksibilitas. Teknik hybrid seperti ini sering ditemui di perusahaan besar.

const resolvers = {
  Query: {
    users: async (_, __, { db }) => {
      const users = await db.user.findMany();
      return users.map(user => ({
        ...user,
        premiumStatus: computePremiumStatus(user)
      }))
    }
  },
  User: {
    orders: (parent, _, { db }) => db.order.findMany({ where: { userId: parent.id } })
  }
}
  • Bagian Query tetap efisien (otomatis),
  • Bagian field spesifik (orders, premiumStatus) bisa manual-custom.

Best Practice Engineering

  1. Mulai dari Otomatis: Untuk prototyping/MVP.
  2. Refactor ke Manual Saat Diperlukan: Transformasi, optimasi, audit, security.
  3. Gunakan Middleware: Untuk logging/validasi tanpa repot mengubah resolver manual satu per satu.
  4. Automate Boring Stuff: Partial automation, gunakan code generator.
  5. Test Resolver Secara Mendalam: Karena bug resolver berdampak langsung ke user.
  6. Monitor Overfetching/Underfetching: Resolver otomatis rawan ambil data terlalu banyak/kurang.

Penutup

Menangani resolver — baik otomatis maupun manual — adalah tentang trade-off antara kecepatan development dan depth of control. Automate when you can. Go manual when you must. Tidak ada satu silver bullet. Engineering yang baik mengerti kapan harus mengoptimasi, dan kapan cukup menggunakan otomatisasi.

Selalu ukur kebutuhan proyek Anda, dan jangan ragu untuk menggabungkan keduanya dalam arsitektur modern. Pengalaman saya di beberapa perusahaan skala nasional membuktikan, gaya hybrid sering menjadi solusi terbaik untuk masalah nyata di dunia produksi.

Silakan bagikan pengalaman kalian tentang menggunakan atau membangun resolver—otomatis, manual, atau gabungan, di kolom komentar!


Referensi:


Salam rekayasa,
Ariv—Senior Software Engineer

comments powered by Disqus