23 Modularisasi File Resolver dan Skema: Pendekatan Terstruktur Membangun GraphQL API
Membangun API GraphQL seringkali membawa kita pada masalah-masalah modularitas terhadap skema dan resolver. Jika dibiarkan tumbuh secara monolitik, skema dan resolver mudah menjadi susah dibaca, rawan konflik import, dan berisiko besar ketika di-maintain engineer lain — atau bahkan kita sendiri, di masa depan.
Pada artikel kali ini, saya akan membahas teknik modularisasi file resolver dan skema dalam proyek GraphQL NodeJS menggunakan apollo-server
, serta mengilustrasikan praktik terbaik dengan contoh kode, simulasi skenario, hingga diagram modularisasi menggunakan mermaid. Semua dengan gaya sederhana namun profesional, sebagaimana kita para engineer saling berbagi insight di Medium.
Mengapa Butuh Modularisasi?
Mari kita mulai dari permasalahan umum — biasanya, dalam fase awal, kita mendefinisikan seluruh skema dan resolver dalam satu file, misalnya schema.js
dan resolvers.js
, seperti ini:
// schema.js
const { gql } = require('apollo-server');
const typeDefs = gql`
type Query {
books: [Book]
}
type Book {
title: String
author: String
}
`;
module.exports = typeDefs;
// resolvers.js
const resolvers = {
Query: {
books: () => [{ title: "1984", author: "Orwell" }]
}
};
module.exports = resolvers;
Ini baik untuk prototipe atau skala sangat kecil. Tapi dengan bertambahnya resource (misalnya entities baru seperti User, Post, Comment), file tersebut makin membengkak. Semua hal numpuk dalam satu file, kolaborasi jadi sulit, testing jadi repot, risiko conflict merge berlangsung tinggi.
Rangkuman Tantangan Tanpa Modularisasi
Masalah | Efek Negatif |
---|---|
File menumpuk | Sulit navigasi & refactor |
Naming conflict | Error tidak terdeteksi sebelum runtime |
Sulit diuji | Teardown & setup test jadi rumit |
Merge conflict | Sering tabrakan saat kolaborasi |
Prinsip Modularisasi Resolver & Skema
Goal: Setiap entity (domain) memiliki file skema dan resolver sendiri, lalu di-merge otomatis. Mirip konsep “feature folder” pada frontend (misal React).
Contohnya, kita punya struktur folder seperti ini:
src/
├── graphql/
| ├── book/
| | ├── typeDefs.js
| | └── resolvers.js
| ├── user/
| | ├── typeDefs.js
| | └── resolvers.js
| └── index.js
└── server.js
Benefit:
- Mudah scale up/down fitur
- Tim lain bisa kolaborasi tanpa geser file utama
- Test per domain/entity
- Maintainable & readable
Implementasi Modular GraphQL
Mari kita bahas step-by-step cara modularisasi file skema dan resolver.
1. Definisikan Schema dan Resolver per Domain
1.1. Book Module
// src/graphql/book/typeDefs.js
const { gql } = require('apollo-server');
const bookTypeDefs = gql`
type Book {
id: ID!
title: String!
author: String!
}
extend type Query {
books: [Book!]!
bookById(id: ID!): Book
}
`;
module.exports = bookTypeDefs;
// src/graphql/book/resolvers.js
const bookResolvers = {
Query: {
books: () => [...], // bisa diisi dummy/mock data
bookById: (_, { id }) => {...}
}
};
module.exports = bookResolvers;
1.2. User Module
// src/graphql/user/typeDefs.js
const { gql } = require('apollo-server');
const userTypeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
extend type Query {
users: [User!]!
userById(id: ID!): User
}
`;
module.exports = userTypeDefs;
// src/graphql/user/resolvers.js
const userResolvers = {
Query: {
users: () => [...],
userById: (_, { id }) => {...}
}
};
module.exports = userResolvers;
2. Root Skema (“Stitching”)
Kita butuh satu “root” skema dan resolver, biasanya di graphql/index.js
:
// src/graphql/index.js
const { gql } = require('apollo-server');
const { mergeTypeDefs, mergeResolvers } = require('@graphql-tools/merge');
const bookTypeDefs = require('./book/typeDefs');
const userTypeDefs = require('./user/typeDefs');
const bookResolvers = require('./book/resolvers');
const userResolvers = require('./user/resolvers');
// Root type Query (perlu jika menggunakan extend type di module)
const rootTypeDefs = gql`
type Query
`;
const typeDefs = mergeTypeDefs([
rootTypeDefs, bookTypeDefs, userTypeDefs
]);
const resolvers = mergeResolvers([
bookResolvers, userResolvers
]);
module.exports = { typeDefs, resolvers };
Note: Package
@graphql-tools/merge
sangat membantu stitch schema/resolver dengan clean.
3. Setup Server
// src/server.js
const { ApolloServer } = require('apollo-server');
const { typeDefs, resolvers } = require('./graphql');
const server = new ApolloServer({
typeDefs,
resolvers
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Simulasi Skenario Penambahan Modul
Bagaimana jika product owner minta menambah fitur baru, misalnya “Comments”?
Cukup tambahkan folder baru:
src/graphql/comment/
├── typeDefs.js
└── resolvers.js
Lalu, import ke src/graphql/index.js
:
// ...existing code ...
const commentTypeDefs = require('./comment/typeDefs');
const commentResolvers = require('./comment/resolvers');
const typeDefs = mergeTypeDefs([
rootTypeDefs, bookTypeDefs, userTypeDefs, commentTypeDefs
]);
const resolvers = mergeResolvers([
bookResolvers, userResolvers, commentResolvers
]);
Done! Tanpa otak-atik file lain.
Ilustrasi Modular Initiation Flow
Mari visualisasikan arsitektur modularisasi ini dengan mermaid diagram.
graph TD A[Server.js] --> B[graphql/index.js] B --> C[book/typeDefs.js & resolvers.js] B --> D[user/typeDefs.js & resolvers.js] B --> E[comment/typeDefs.js & resolvers.js]
Tabel Perbandingan Sebelum vs Sesudah Modularisasi
Aspek | Monolitik | Modular |
---|---|---|
Penambahan fitur | Sulit, rawan conflict | Sangat mudah |
Teamwork | Sering merge crash | File terpisah, aman |
Testing | E2E dominan | Bisa unit per module |
Maintainability | Menurun seiring waktu | Minimal changes |
Scalability | Lemah | Mudah bertambah |
Tips Modularisasi Resolver & Schema
- Gunakan folder per domain
- Mudah tracking, scale, dan debug masalah.
- Sediakan folder root untuk glue/stitching
- Misal
/graphql/index.js
.
- Misal
- Jangan lupa root
type Query
- Kalau setiap typeDefs pakai
extend type Query
, perlu roottype Query
untuk initial schema.
- Kalau setiap typeDefs pakai
- Pisahkan antara schema & resolver
- Uji dan refactor lebih fleksibel.
- Gunakan tools merge
- Integrasi skema/resolver jangan hardcode, pakai helper lib.
- Tambahkan test per module
- Unit test tiap resolver & schema.
Penutup
Dengan modularisasi schema dan resolver, GraphQL API kita jauh lebih maintainable, scalable, dan nyaman untuk kolaborasi. Teknik ini bukan hanya best practice “kekinian”, tapi sudah terbukti jadi fundamental di berbagai codebase GraphQL production berskala besar.
Dengan ilustrasi kode, diagram, dan simulasi kasus di atas, saya harap Anda makin mantap membangun GraphQL yang siap scale-up secara profesional. Bagikan artikel ini jika menurut Anda bermanfaat — dan jangan ragu diskusi di kolom komentar, siapa tahu kita bisa saling belajar untuk modulasi berikutnya!
Happy coding, dan salam modular! 🚀
Resources:
45 Cara Menggunakan `option` di Protobuf
Artikel Terhangat
26 Apa Itu Mutation dan Kapan Digunakan?
07 Jul 2025
48 Custom Options di Protobuf
07 Jul 2025
47 Reserved Fields dan Reserved Numbers
07 Jul 2025
23 Modularisasi File Resolver dan Skema
07 Jul 2025
45 Cara Menggunakan `option` di Protobuf
07 Jul 2025

26 Apa Itu Mutation dan Kapan Digunakan?

48 Custom Options di Protobuf

47 Reserved Fields dan Reserved Numbers

23 Modularisasi File Resolver dan Skema
