Belajar GraphQL - Koneksi ke Database dan External APIs
Episode 8 of 51

Belajar GraphQL - Koneksi ke Database dan External APIs

Episode 8 menghubungkan GraphQL ke sumber data nyata: pola data source, integrasi SQL dengan Prisma, integrasi NoSQL dengan MongoDB dan Redis, class RESTDataSource untuk API eksternal, serta best practices separation of concerns antara resolver dan data layer.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Server GraphQL kalian sudah berjalan, tapi belum ada data nyata. Episode 8 mengubah itu: kita menghubungkan GraphQL ke database dan API eksternal. Inilah titik di mana GraphQL benar-benar berguna — mengambil data dari berbagai sumber dan menyajikannya dalam satu endpoint.

Kita akan membahas pola data source, integrasi SQL dengan Prisma, integrasi NoSQL dengan MongoDB, penggunaan Redis untuk caching, class RESTDataSource untuk mengonsumsi API eksternal, dan best practices separation of concerns antara resolver dan data layer.

Data Source Patterns

Jenis Data Source

Sebuah resolver bisa mengambil data dari mana saja. Empat pola yang paling umum:

  • REST API sebagai data source, lewat RESTDataSource.
  • Database langsung, baik SQL maupun NoSQL.
  • GraphQL-to-GraphQL, yaitu memanggil service GraphQL lain (basis dari federation di episode 22).
  • Third-party services seperti payment gateway dan mail service.

Pola kuncinya tetap sama: resolver jangan berisi logika data langsung, melainkan mendelegasikan ke layer data yang terpisah. Inilah yang disebut separation of concerns.

SQL Database Integration

Prisma dengan PostgreSQL

Prisma adalah ORM modern untuk TypeScript yang menghasilkan tipe dari skema database — sangat cocok dipasangkan dengan GraphQL. Setup-nya:

Setup Prisma
npm install @prisma/client
npm install -D prisma
npx prisma init

Lalu definisikan model di schema.prisma:

JSModel Prisma
model User {
  id        Int      @id @default(autoincrement())
  username  String   @unique
  email     String   @unique
  posts     Post[]
}
 
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  body      String
  authorId  Int
  author    User     @relation(fields: [authorId], references: [id])
}

Jalankan npx prisma migrate dev untuk membuat tabel, lalu masukkan client Prisma ke context:

JSPrisma di dalam context
import { PrismaClient } from "@prisma/client";
 
const prisma = new PrismaClient();
 
const server = new ApolloServer({
  typeDefs,
  resolvers,
});
 
const { url } = await startStandaloneServer(server, {
  context: async () => ({ prisma }),
});

Resolver kini bisa memakai ctx.prisma:

JSResolver dengan Prisma
Query: {
  post: (_, args, ctx) =>
    ctx.prisma.post.findUnique({ where: { id: Number(args.id) } }),
},

Connection Pooling dan Optimasi

Di production, gunakan connection pooling seperti PgBouncer, dan buat query yang selektif agar tidak mengambil kolom berlebihan. Masalah N+1 yang timbul dari pola resolver chain akan diselesaikan dengan DataLoader di episode 9.

NoSQL Database Integration

MongoDB dengan Mongoose

Untuk database dokumen, gunakan MongoDB dengan Mongoose:

Install Mongoose
npm install mongoose
JSModel Mongoose
import { Schema, model } from "mongoose";
 
const userSchema = new Schema({
  username: { type: String, required: true, unique: true },
  email: String,
});
 
export const User = model("User", userSchema);

Redis untuk Caching

Redis sangat berguna sebagai cache layer antara resolver dan database. Pola yang umum: cek cache dulu, jika kosong ambil dari database lalu simpan ke cache dengan TTL. Kita akan membedah strategi caching menyeluruh di episode 20, termasuk cara memakai Redis untuk menyimpan hasil query.

Apollo DataSource Class

RESTDataSource

Untuk mengonsumsi REST API dari dalam resolver, Apollo menyediakan class RESTDataSource. Ini memberikan batching otomatis, caching per request, dan de-duplikasi request yang sangat berguna:

JSRESTDataSource untuk API eksternal
import { RESTDataSource } from "@apollo/datasource-rest";
 
export class UsersAPI extends RESTDataSource {
  baseURL = "https://api.example.com/";
 
  async getUser(id) {
    return this.get(`users/${id}`);
  }
 
  async getPostsByUser(userId) {
    return this.get("posts", { params: { userId } });
  }
}

Instansiasi data source ini lalu taruh di context. Pola ini adalah fondasi strategi migrasi REST ke GraphQL di episode 47 — REST API yang sudah ada bisa dibungkus tanpa ditulis ulang.

Best Practices

Repository Pattern

Prinsip utama: resolver tetap tipis dan hanya mengatur "cara client meminta data", sementara layer data mengatur "dari mana data didapat". Implementasi praktisnya:

  • Pisahkan akses data ke file repository atau service sendiri.
  • Masukkan semua dependency (prisma, mongoose, REST client) ke context.
  • Jangan menulis logika bisnis yang rumit di dalam resolver.
JSPemisahan resolver dan data layer
import { UserRepository } from "./data/user.repository";
 
const resolvers = {
  Query: {
    user: (_, args, ctx) => ctx.repos.users.findById(args.id),
  },
};

Pola ini membuat resolver mudah dites (episode 21), mudah diganti sumber datanya, dan mudah dioptimasi secara terpusat.

Penutup

Inti yang harus dibawa pulang:

  • Resolver mendelegasikan akses data ke data layer, bukan menulis query langsung.
  • Prisma memberi tipe aman untuk PostgreSQL; Mongoose untuk MongoDB; Redis untuk cache.
  • RESTDataSource membungkus API eksternal dengan batching dan caching otomatis.
  • Semua dependency di-expose lewat context agar mudah diakses dan dites.
  • Repository pattern menjaga separation of concerns dan keterbacaan.

Di episode 9 selanjutnya kalian akan mempelajari DataLoader dan N+1 problem — apa itu N+1, mengapa GraphQL mudah memicunya, cara batching dan caching dengan DataLoader, integrasi loader ke dalam context per request, hingga teknik memonitor perbaikan performa. Masalah klasik GraphQL akan kalian taklukkan!

Belajar GraphQL - Koneksi ke Database dan External APIs | Belajar GraphQL