tutorial

65 Skema Dinamis dan Custom Scalar Types

65 Skema Dinamis dan Custom Scalar Types: Menjelajah Dunia Type System yang Lebih Fleksibel

Dalam dunia modern pengembangan perangkat lunak, API tidak hanya sekadar jembatan antar sistem, tapi juga kontrak yang menentukan cara data dipertukarkan. Salah satu pilar utama dalam mendefinisikan API, khususnya dalam konteks GraphQL atau gRPC, adalah type system. Artikel ini akan mengupas dua aspek advanced yakni skema dinamis dan custom scalar types. Kita akan melihat alasan, implementasi, serta contoh pragmatis penggunaan keduanya.


Mengapa Skema Dinamis?

Pada banyak kasus, kebutuhan bisnis dapat berubah dengan cepat. Jika sebuah API memaksa struktur data yang kaku (rigid) dan sulit beradaptasi, maka perubahan-perubahan kecil pun bisa berujung pada deployment besar-besaran. Maka dari itu, muncul konsep skema dinamis—di mana struktur data bisa disesuaikan atau bahkan didefinisikan oleh pengguna API tanpa harus melakukan hardcode di tingkat kode sumber.

Skema Dinamis membuat API menjadi:

  • Lebih mudah beradaptasi
  • Minim downtime karena deploy schema baru
  • Mendukung use-case custom/sesuai kebutuhan

Contoh Skenario Skema Dinamis

Bayangkan aplikasi SaaS yang menawarkan penyimpanan data custom untuk tiap client. Setiap tenant ingin menyimpan data dengan struktur yang berbeda (misal: HR, Inventory, atau CRM). Akan sangat memberatkan jika kita harus membuat schema baru untuk setiap tenant.


Sekilas Custom Scalar Types

Tipe data scalar adalah tipe paling dasar seperti Int, Float, String, dst. Namun, kadang tipe data bisnis jauh lebih kaya, dan menggunakan tipe dasar bisa membuka risiko data tidak valid, misal: menyimpan email sebagai String.

Di sinilah custom scalar types berperan:

  • Membuat codebase lebih type safe
  • Menyederhanakan validasi di sisi backend
  • Dokumentasi API jadi lebih jelas

Simulasi: Dynamic Schema & Custom Scalar di GraphQL

Mari masuk ke contoh nyata! Kita akan menggunakan GraphQL yang memang sangat flexible baik dalam mendefinisikan schema secara dinamis maupun mendukung custom scalar types.

1. Membuat Custom Scalar Type

Misal, aplikasi kita butuh validasi khusus untuk tipe PhoneNumber.

// src/schema/scalars.js
const { GraphQLScalarType, Kind } = require('graphql');

const PhoneNumber = new GraphQLScalarType({
  name: 'PhoneNumber',
  description: 'Custom Phone Number Scalar',
  serialize(value) {
    return value; // Asumsi value sudah berbentuk string valid
  },
  parseValue(value) {
    if (!/^\+628[0-9]{8,}$/.test(value)) {
      throw new Error('Invalid phone number. Must start with +628');
    }
    return value;
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING && /^\+628[0-9]{8,}$/.test(ast.value)) {
      return ast.value;
    }
    throw new Error('Invalid phone number');
  },
});

module.exports = { PhoneNumber };

Dengan cara ini, field yang bertipe PhoneNumber akan selalu tervalidasi.

2. Definisi Skema Dinamis

GraphQL biasanya menggunakan schema statis, tapi ada strategi agar schema bisa berubah di runtime:

Implementasi Skema Dinamis

Katakan, client boleh menentukan sendiri field apa yang ingin disimpan di objek Customer. Contoh:

// src/schema/dynamicSchema.js
const { 
  GraphQLObjectType, 
  GraphQLSchema, 
  GraphQLString,
  GraphQLScalarType 
} = require('graphql');

// Dynamic function generates new fields:
function generateCustomerType(fieldDefinitions) {
  const fields = {};
  fieldDefinitions.forEach(def => {
    fields[def.name] = { type: GraphQLString, description: def.desc };
  });
  return new GraphQLObjectType({
    name: 'Customer',
    fields,
  });
}

const dynamicFieldDefinitions = [
  { name: 'firstName', desc: 'Nama Depan Pelanggan' },
  { name: 'lastName', desc: 'Nama Belakang Pelanggan' },
  { name: 'phone', desc: 'Nomor Telepon', type: 'PhoneNumber' },
];

const CustomerType = generateCustomerType(dynamicFieldDefinitions);

const QueryType = new GraphQLObjectType({
  name: 'Query',
  fields: {
    customer: {
      type: CustomerType,
      resolve: () => ({ firstName: 'Ahmad', lastName: 'Yani', phone: '+62812345678' }),
    }
  }
});

const schema = new GraphQLSchema({ query: QueryType });

module.exports = { schema };

Dengan pendekatan ini, struktur Customer dapat berubah cukup dengan mengubah array dynamicFieldDefinitions, tidak perlu mengubah kode schema secara manual.


Kelebihan & Tantangan

KelebihanTantangan
Sangat fleksibel, cepat adaptasiMeningkatkan risiko runtime error
Mendukung multi-tenant / custom dataLebih sulit divalidasi secara static
Validasi lebih baik via custom scalarRisk data leaky tanpa schema ketat
Schema bisa diubah tanpa re-deployCode semakin kompleks

Diagram Alur: Proses Pembuatan Skema Dinamis

flowchart TD
    A[Inisiasi aplikasi] --> B{Ada perubahan struktur data?}
    B -- "Ya" --> C[Muat/Generate Field Definitions dari DB/config]
    B -- "Tidak" --> D[Gunakan Schema yang sudah ada]
    C --> E[Bangun ulang GraphQL Schema di runtime]
    E --> F[Jalankan API Server]
    D --> F

Studi Kasus: Multi-Tenant SaaS

Sebuah SaaS ingin setiap tenant bisa mengkostumisasi field Lead. Tenant A ingin leadStatus, tenant B ingin industry & budget. Dengan dynamic schema generator, admin dapat menetapkan field mana saja yang mau digunakan:

Contoh Konfigurasi Tenant:

TenantFieldType
AlphaleadStatusString
BetaindustryString
BetabudgetInt
GammaphonePhoneNumber

Mekanisme generate schema sesuai table/DB konfigurasi.


Best Practice & Tips

  1. Simpan definisi schema dinamis di luar kode (DB/file store), jangan hardcode.
  2. Custom scalar harus didukung baik di client dan server, misal via dokumentasi.
  3. Selalu logging error runtime schema untuk mencegah silent bug.
  4. Gunakan generator/type-factory agar pembuatan schema tetap DRY.
  5. Jika scalable, cache schema hasil generate agar startup lebih cepat.

Penutup

Dengan menerapkan skema dinamis dan custom scalar types, arsitektur aplikasi API Anda menjadi jauh lebih adaptif, mudah berkembang, serta lebih robust dari sisi keamanan data. Namun, fleksibilitas ekstra ini datang dengan trade-off berupa peningkatan kompleksitas dan risiko error runtime yang harus dikelola dengan baik.

Dengan desain dan implementasi yang hati-hati, kedua konsep ini bisa menjadi pembeda utama antara produk SaaS atau API yang skalabel versus yang mudah deadlock perubahan.

Seperti biasa, kunci utama adalah eksperimen dan review: jangan ragu mencoba, tapi disiplin dalam validasi dan monitoring.
Selamat membangun API masa depan! 🚀

comments powered by Disqus