Episode 18 membahas advanced schema design: prinsip berpikir dalam grafik, desain relasi one-to-one sampai many-to-many, global object identification dengan Node interface, mutation payload design, strategi evolusi API dengan @deprecated, hingga modularisasi dan domain-driven schema.

Schema adalah keputusan arsitektur paling penting dalam aplikasi GraphQL. Sekali dirilis ke client, schema sulit diubah. Episode 18 membahas advanced schema design patterns yang dipakai tim berpengalaman untuk merancang schema yang tahan uji waktu.
Kita akan mempelajari prinsip desain, cara memodelkan relasi, global object identification, mutation payload design, strategi evolusi API, dan teknik modularisasi schema.
GraphQL memaksa kalian berpikir dalam grafik: entitas sebagai node, relasi sebagai edge. Sebelum menulis SDL, petakan domain kalian sebagai grafik — apa node-nya, apa relasinya, dan dari node mana client paling natural mulai menjelajah.
Prinsip kunci: schema dirancang untuk kebutuhan client, bukan struktur database. Biarkan database tetap normal, tetapi susun graph sedemikian rupa sehingga client bisa mengambil data dengan cara yang alami.
Keputusan nullable versus non-nullable (episode 3) punya konsekuensi besar. Prinsip yang dianut banyak tim:
Hati-hati dengan non-null berantai: jika Post.author non-null dan resolver author gagal, seluruh post ikut gagal. Gunakan non-null secara berani hanya pada field yang benar-benar dijamin.
Relasi domain dipetakan ke field objek:
User.profile.User.posts, sebaiknya dengan pagination (episode 12).User.teams dan Team.members.type Team {
id: ID!
name: String!
members: [TeamMember!]!
}
type TeamMember {
user: User!
role: String!
joinedAt: DateTime!
}Circular references (misalnya User.teams dan Team.members) aman di GraphQL selama query tidak wajib menyertakan semua level. GraphQL melayani grafik ber-siklus tanpa masalah.
Relay menentukan pola global identification: setiap objek memiliki ID global unik, dan sebuah interface Node memungkinkan mengambil objek apa pun hanya dengan ID-nya:
interface Node {
id: ID!
}
type User implements Node {
id: ID!
username: String!
}
type Query {
node(id: ID!): Node
}ID global biasanya berisi informasi tipe (misalnya hasil encode Buffer.from("User:123").toString("base64")), sehingga server bisa menentukan tipe dan mengambil objek yang tepat:
Query: {
node: async (_, args, ctx) => {
const [type, id] = Buffer.from(args.id, "base64").toString().split(":");
if (type === "User") return ctx.loaders.userById.load(id);
if (type === "Post") return ctx.loaders.postById.load(id);
return null;
},
},Manfaatnya: client bisa me-refetch objek apa pun dengan satu API seragam, dan cache client (episode 20) mendapat key ID global yang stabil untuk normalisasi.
Prinsip payload mutation yang sering dipakai:
clientMutationId yang dikirim client untuk korelasi response.edge dan node yang diubah, atau updatedEdge sesuai Relay pola, sehingga client bisa memperbarui cache tanpa query ulang.type CreatePostPayload {
edge: PostEdge!
node: Post!
errors: [FieldError!]
}
type Mutation {
createPost(input: CreatePostInput!): CreatePostPayload!
}Schema tidak bisa di-versioning seperti REST (/v1, /v2). Strateginya adalah evolusi tanpa breaking change:
@deprecated lalu beri pengganti.type User {
id: ID!
username: String!
fullName: String
@deprecated(reason: "Gunakan nama field kombinasi first_name dan last_name")
firstName: String
lastName: String
}Perubahan yang berpotensi breaking (misalnya mengubah tipe atau menambah non-null) dideteksi otomatis oleh tools seperti GraphQL Inspector dan Apollo Studio schema checks — akan dibahas di episode 21 dan 32.
Schema raksasa sulit dirawat dan di-review. Strategi modularisasi:
# modul order.graphql
extend type User {
orders(first: Int): OrderConnection!
}Setiap modul dimiliki tim masing-masing dan digabung di komposisi akhir. Untuk skala besar, federation di episode 22 dan 36 memberikan kepemilikan schema per service yang lebih kuat.
Inti yang harus dibawa pulang:
@deprecated; modularisasi schema per domain.Di episode 19 selanjutnya kalian akan mempelajari optimasi performa GraphQL — analisis query dan identifikasi bottleneck, strategi caching, Automatic Persisted Queries, field-level caching dengan memoization, batching dan DataLoader optimization, hingga monitoring performa. Server kalian akan melayani query dengan jauh lebih cepat!