Skip to main content
BlogWeb Dev

GraphQL vs REST di 2025: Mana yang Dipilih untuk Proyek Berikutnya?

Perbandingan jujur GraphQL dan REST — data adopsi, benchmark performa, dan kerangka yang saya gunakan untuk memilih antara keduanya.

Matthews Wong

Software Engineer

Juni 202510 menit baca
Web Dev

REST mendukung 83% dari semua layanan web dan 76% API publik. GraphQL telah melihat lonjakan 340% dalam adopsi Fortune 500 sejak 2023. Dua fakta ini hidup berdampingan tanpa kontradiksi: REST tetap menjadi default, GraphQL mendapatkan momentum serius dalam konteks enterprise. Saya telah membangun API produksi di keduanya, dan pandangan saya pragmatis — GraphQL benar-benar lebih baik untuk masalah tertentu, dan REST benar-benar lebih baik untuk masalah lain.

DimensiRESTGraphQL
Pengambilan dataButuh beberapa round trip untuk resource terkait, median sekitar 250msCukup satu round trip, field yang benar-benar dibutuhkan, median sekitar 180ms
Caching HTTPBisa di-cache secara default lewat header Cache-ControlTidak bisa di-cache secara default karena semua request lewat POST /graphql
Tooling & ekosistemSudah matang: Swagger/OpenAPI, Postman, klien HTTP apa punMasih lebih baru: perlu schema, resolver, dan DataLoader
Model otorisasiDiperiksa per endpointDiperiksa per field, introspection wajib dimatikan di production
Update real-timePerlu polling atau kelola WebSocket secara manualSudah ada subscription bawaan, mengurangi overhead polling hingga 80 persen
Paling cocok untukAPI publik, CRUD sederhana, komunikasi antar-serverAplikasi multi-klien, dashboard, relasi data yang kompleks
Kompleksitas di productionButuh lapisan BFF untuk menggabungkan banyak panggilanButuh DataLoader dan pembatasan kompleksitas query

Di Mana REST Menang

REST menang dalam kesederhanaan, caching, dan kematangan ekosistem. API REST adalah sekumpulan URL dengan HTTP verb — klien HTTP mana pun dalam bahasa apa pun dapat mengonsumsinya tanpa library. Respons GET dapat di-cache secara default di lapisan HTTP (CDN, cache browser, cache proxy) dengan header Cache-Control standar. Ekosistem tooling sangat besar: Swagger/OpenAPI untuk dokumentasi, Postman untuk pengujian.

Karakteristik Performa REST

REST mencapai ~250ms waktu respons median untuk permintaan sumber daya standar. Bottleneck performa untuk REST biasanya overfetching (mendapatkan lebih banyak bidang dari yang diperlukan) dan beberapa round trip (permintaan N+1 untuk mendapatkan sumber daya terkait). Untuk klien mobile yang membutuhkan profil pengguna, pesanan terbaru, dan jumlah notifikasi dalam satu layar, REST memerlukan tiga panggilan API terpisah.

Di Mana GraphQL Menang

GraphQL menang dalam presisi pengambilan data dan hubungan data yang kompleks. Satu kueri GraphQL dapat mengambil pengguna, 5 pesanan terakhir mereka, item setiap pesanan, dan detail produk — dalam satu round trip, dengan tepat bidang yang dibutuhkan klien. GraphQL mengurangi panggilan API hingga 60% dalam skenario agregasi data yang kompleks dan mencapai ~180ms latensi median untuk kueri yang akan memerlukan beberapa round trip REST.

REST: 3 round trips to build a user dashboard
─────────────────────────────────────────────
Client → GET /api/users/42          → { id, name, email }
Client → GET /api/users/42/orders   → [{ id, total, status }]
Client → GET /api/notifications/42  → { unread: 3 }
Total: 3 requests, ~750ms on mobile 4G

GraphQL: 1 round trip, exact fields
─────────────────────────────────────────────
Client → POST /graphql
  query {
    user(id: "42") {
      name
      email
      recentOrders(limit: 5) { id total status }
      notificationCount
    }
  }
→ { user: { name, email, recentOrders: [...], notificationCount: 3 } }
Total: 1 request, ~180ms on mobile 4G ✓

Adoption (2025):
  REST:    83% of all web services, 76% of public APIs
  GraphQL: 340% growth in Fortune 500 adoption since 2023
           67% of adopters report improved dev productivity
           89% would choose GraphQL again for similar projects

Dari pengalaman saya membangun API NestJS: gunakan GraphQL untuk API yang menghadap klien di mana beberapa klien (web, mobile, mitra) mengambil data yang sama dalam bentuk berbeda. Gunakan REST untuk integrasi server-ke-server, API publik, dan operasi CRUD sederhana. Pendekatan hybrid — GraphQL untuk API frontend, REST untuk panggilan microservice-ke-microservice — bekerja dengan baik karena mengoptimalkan setiap lapisan untuk kasus penggunaan aktualnya.

Tantangan GraphQL di Produksi

Fleksibilitas GraphQL menciptakan tantangan produksi yang tidak ada di REST. Masalah N+1: kueri GraphQL dapat memicu N kueri database untuk N item dalam daftar. Solusinya adalah DataLoader, yang membatch dan mendeduplikasi panggilan database. Kompleksitas kueri: klien dapat menulis kueri bersarang dalam yang menyebabkan beban database eksponensial. Caching: respons GraphQL tidak dapat di-cache di lapisan HTTP secara default karena semua permintaan pergi ke POST /graphql.

Keamanan: GraphQL vs REST

API REST memiliki area permukaan yang terdefinisi — setiap endpoint eksplisit. GraphQL memiliki bahasa kueri terbuka. Ini membuat otorisasi lebih kompleks: setiap resolver bidang harus memeriksa apakah pengguna yang meminta diizinkan untuk melihat bidang itu. Di REST, Anda memeriksa otorisasi per endpoint. Di GraphQL, Anda memeriksa per bidang — melewatkan pemeriksaan bidang adalah potensi kebocoran data.

// app.module.ts — NestJS with both REST and GraphQL
import { GraphQLModule } from '@nestjs/graphql'
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: true,       // generate schema from decorators
      sortSchema: true,
      introspection: process.env.NODE_ENV !== 'production', // security!
      playground: process.env.NODE_ENV !== 'production',
    }),
  ],
})

// invoices.resolver.ts — GraphQL resolver
@Resolver(() => Invoice)
export class InvoicesResolver {
  constructor(
    private invoicesService: InvoicesService,
    private readonly invoiceItemsLoader: InvoiceItemsLoader, // DataLoader for N+1
  ) {}

  @Query(() => [Invoice])
  async invoices(@Args('cursor') cursor?: string): Promise<Invoice[]> {
    return this.invoicesService.findAll(cursor)
  }

  @ResolveField(() => [InvoiceItem])
  async items(@Parent() invoice: Invoice): Promise<InvoiceItem[]> {
    // DataLoader batches all invoice item requests into one DB query
    return this.invoiceItemsLoader.load(invoice.id)
  }

  @Subscription(() => Invoice)
  invoiceUpdated() {
    return pubSub.asyncIterator('invoiceUpdated') // real-time via WebSocket
  }
}

// invoices.controller.ts — REST controller (same service layer)
@Controller({ path: 'invoices', version: '2' })
export class InvoicesController {
  constructor(private readonly invoicesService: InvoicesService) {}

  @Get()
  findAll(@Query('cursor') cursor?: string) {
    return this.invoicesService.findAll(cursor) // same service method!
  }
}

Subscriptions: Keunggulan Async GraphQL

GraphQL subscriptions melalui WebSockets menyediakan push data real-time — klien berlangganan event dan menerima pembaruan tanpa polling. GraphQL subscriptions mengurangi overhead polling hingga 80% dibandingkan polling REST untuk data real-time. Untuk sistem ERP di mana pengguna perlu melihat pembaruan status pesanan secara real-time, subscription GraphQL lebih bersih.

Fitur introspeksi GraphQL memungkinkan klien mengkueri skema penuh — setiap tipe, bidang, dan hubungan. Dalam pengembangan, ini mendukung GraphQL Playground dan pembuatan tipe. Dalam produksi, ini mengekspos seluruh model data Anda kepada siapa pun yang dapat menjangkau endpoint Anda. Nonaktifkan introspeksi di produksi: `introspection: process.env.NODE_ENV !== 'production'`.

Kerangka Keputusan

Saya menggunakan pohon keputusan ini: Beberapa klien dengan kebutuhan data berbeda → GraphQL. CRUD sederhana dengan bentuk data standar → REST. API publik dengan pengembang pihak ketiga → REST. Data real-time → subscriptions GraphQL. Caching kritis → REST atau GraphQL dengan persisted queries. Tim baru di codebase → REST (kurva belajar lebih rendah). Hubungan entitas kompleks, agregasi dashboard → GraphQL.

Menjalankan Keduanya di NestJS

NestJS membuatnya mudah untuk menjalankan REST dan GraphQL secara bersamaan dalam aplikasi yang sama. REST controllers dan GraphQL resolver dapat berbagi lapisan layanan yang sama. Arsitektur ini memungkinkan Anda mulai dengan REST dan menambahkan GraphQL nanti tanpa menulis ulang logika bisnis Anda.

Sumber & Bacaan Lebih Lanjut

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Kapan sebaiknya memilih GraphQL daripada REST?

GraphQL adalah pilihan yang lebih baik ketika beberapa klien (web, mobile, mitra) perlu mengambil data yang sama dalam bentuk berbeda, atau ketika Anda memiliki hubungan entitas yang kompleks dan agregasi dashboard yang membutuhkan banyak round trip. GraphQL mengurangi panggilan API hingga 60% dalam skenario agregasi data yang kompleks dan mencapai sekitar 180ms latensi median untuk kueri yang sebaliknya memerlukan beberapa panggilan REST. Untuk operasi CRUD sederhana, API publik, atau kasus di mana HTTP caching sangat penting, REST tetap menjadi pilihan yang lebih kuat.

Apa perbedaan performa utama antara GraphQL dan REST?

REST mencapai sekitar 250ms waktu respons median untuk permintaan sumber daya standar, tetapi menderita akibat overfetching dan N+1 round trip — misalnya, layar mobile yang membutuhkan profil pengguna, pesanan terbaru, dan jumlah notifikasi memerlukan tiga panggilan API terpisah. GraphQL menyelesaikan data yang sama dalam satu round trip dengan sekitar 180ms latensi median. Komprominya adalah respons GraphQL tidak dapat di-cache di lapisan HTTP secara default karena semua permintaan menuju POST /graphql, sedangkan respons GET REST secara native dapat di-cache melalui CDN dan cache browser.

Apa itu masalah N+1 di GraphQL dan bagaimana solusinya?

Masalah N+1 terjadi ketika kueri GraphQL memicu satu kueri database per item dalam daftar untuk menyelesaikan bidang bersarang, menghasilkan N kueri ekstra untuk N item. Solusi standarnya adalah DataLoader, yang mem-batch dan mendeduplikasi panggilan database tersebut menjadi satu kueri tunggal. Tanpa DataLoader, API GraphQL yang terlihat efisien dari sisi klien dapat menghasilkan beban database yang signifikan di produksi.

Apakah introspeksi GraphQL aman dibiarkan aktif di produksi?

Tidak — introspeksi GraphQL mengekspos seluruh model data Anda (setiap tipe, bidang, dan hubungan) kepada siapa pun yang dapat menjangkau endpoint Anda, yang memberi penyerang informasi yang cukup untuk membuat kueri yang ditargetkan. Rekomendasinya adalah menonaktifkan introspeksi di produksi menggunakan `introspection: process.env.NODE_ENV !== 'production'` dalam konfigurasi modul GraphQL NestJS Anda, dan juga menonaktifkan GraphQL Playground di lingkungan produksi.

Bisakah REST dan GraphQL berjalan bersama dalam satu aplikasi NestJS?

Ya — NestJS mendukung menjalankan keduanya secara bersamaan dalam aplikasi yang sama. REST controllers dan GraphQL resolver dapat berbagi lapisan layanan yang sama, sehingga satu kelas service menangani panggilan endpoint REST maupun panggilan resolver GraphQL tanpa menduplikasi logika bisnis. Modul GraphQL mendaftarkan routernya sendiri di /graphql sementara REST controllers mendaftar di path yang didekorasi, keduanya membaca dari database yang sama melalui metode service yang sama.