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

23 Modularisasi File Resolver dan Skema

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

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:

js
 1// schema.js
 2const { gql } = require('apollo-server');
 3
 4const typeDefs = gql`
 5  type Query {
 6    books: [Book]
 7  }
 8  type Book {
 9    title: String
10    author: String
11  }
12`;
13
14module.exports = typeDefs;
15
16// resolvers.js
17const resolvers = {
18  Query: {
19    books: () => [{ title: "1984", author: "Orwell" }]
20  }
21};
22
23module.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

MasalahEfek Negatif
File menumpukSulit navigasi & refactor
Naming conflictError tidak terdeteksi sebelum runtime
Sulit diujiTeardown & setup test jadi rumit
Merge conflictSering 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:

text
 1src/
 2 ├── graphql/
 3 |    ├── book/
 4 |    |    ├── typeDefs.js
 5 |    |    └── resolvers.js
 6 |    ├── user/
 7 |    |    ├── typeDefs.js
 8 |    |    └── resolvers.js
 9 |    └── index.js
10 └── 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

js
 1// src/graphql/book/typeDefs.js
 2const { gql } = require('apollo-server');
 3
 4const bookTypeDefs = gql`
 5  type Book {
 6    id: ID!
 7    title: String!
 8    author: String!
 9  }
10  extend type Query {
11    books: [Book!]!
12    bookById(id: ID!): Book
13  }
14`;
15
16module.exports = bookTypeDefs;
17
18// src/graphql/book/resolvers.js
19const bookResolvers = {
20  Query: {
21    books: () => [...], // bisa diisi dummy/mock data
22    bookById: (_, { id }) => {...}
23  }
24};
25
26module.exports = bookResolvers;

1.2. User Module

js
 1// src/graphql/user/typeDefs.js
 2const { gql } = require('apollo-server');
 3
 4const userTypeDefs = gql`
 5  type User {
 6    id: ID!
 7    name: String!
 8    email: String!
 9  }
10  extend type Query {
11    users: [User!]!
12    userById(id: ID!): User
13  }
14`;
15
16module.exports = userTypeDefs;
17
18// src/graphql/user/resolvers.js
19const userResolvers = {
20  Query: {
21    users: () => [...],
22    userById: (_, { id }) => {...}
23  }
24};
25
26module.exports = userResolvers;

2. Root Skema (“Stitching”)

Kita butuh satu “root” skema dan resolver, biasanya di graphql/index.js:

js
 1// src/graphql/index.js
 2const { gql } = require('apollo-server');
 3const { mergeTypeDefs, mergeResolvers } = require('@graphql-tools/merge');
 4
 5const bookTypeDefs = require('./book/typeDefs');
 6const userTypeDefs = require('./user/typeDefs');
 7const bookResolvers = require('./book/resolvers');
 8const userResolvers = require('./user/resolvers');
 9
10// Root type Query (perlu jika menggunakan extend type di module)
11const rootTypeDefs = gql`
12  type Query
13`;
14
15const typeDefs = mergeTypeDefs([
16  rootTypeDefs, bookTypeDefs, userTypeDefs
17]);
18const resolvers = mergeResolvers([
19  bookResolvers, userResolvers
20]);
21
22module.exports = { typeDefs, resolvers };
Danger
Note: Package @graphql-tools/merge sangat membantu stitch schema/resolver dengan clean.

3. Setup Server

js
 1// src/server.js
 2const { ApolloServer } = require('apollo-server');
 3const { typeDefs, resolvers } = require('./graphql');
 4
 5const server = new ApolloServer({
 6  typeDefs,
 7  resolvers
 8});
 9
10server.listen().then(({ url }) => {
11  console.log(`🚀  Server ready at ${url}`);
12});

Simulasi Skenario Penambahan Modul

Bagaimana jika product owner minta menambah fitur baru, misalnya “Comments”?
Cukup tambahkan folder baru:

text
1src/graphql/comment/
2 ├── typeDefs.js
3 └── resolvers.js

Lalu, import ke src/graphql/index.js:

js
 1// ...existing code ...
 2const commentTypeDefs = require('./comment/typeDefs');
 3const commentResolvers = require('./comment/resolvers');
 4
 5const typeDefs = mergeTypeDefs([
 6  rootTypeDefs, bookTypeDefs, userTypeDefs, commentTypeDefs
 7]);
 8const resolvers = mergeResolvers([
 9  bookResolvers, userResolvers, commentResolvers
10]);

Done! Tanpa otak-atik file lain.


Ilustrasi Modular Initiation Flow

Mari visualisasikan arsitektur modularisasi ini dengan mermaid diagram.

MERMAID
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

AspekMonolitikModular
Penambahan fiturSulit, rawan conflictSangat mudah
TeamworkSering merge crashFile terpisah, aman
TestingE2E dominanBisa unit per module
MaintainabilityMenurun seiring waktuMinimal changes
ScalabilityLemahMudah bertambah

Tips Modularisasi Resolver & Schema

  1. Gunakan folder per domain
    • Mudah tracking, scale, dan debug masalah.
  2. Sediakan folder root untuk glue/stitching
    • Misal /graphql/index.js.
  3. Jangan lupa root type Query
    • Kalau setiap typeDefs pakai extend type Query, perlu root type Query untuk initial schema.
  4. Pisahkan antara schema & resolver
    • Uji dan refactor lebih fleksibel.
  5. Gunakan tools merge
    • Integrasi skema/resolver jangan hardcode, pakai helper lib.
  6. 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:

Artikel Terkait

💬 Komentar