REST dan GraphQL sama-sama cara client meminta data ke server lewat HTTP. Bedanya: REST punya banyak alamat dengan isi yang sudah ditentukan server, GraphQL punya satu alamat dan client yang menulis isinya. Bayangin dua cara belanja. REST seperti rak paket siap ambil: tiap rak punya satu paket dengan isi tetap, dan paket yang sama bisa disiapkan duluan di depan toko (itu cache). GraphQL seperti loket racikan: kamu sebut persis apa yang kamu mau, sekali antre, tapi pesananmu dibuat setiap kali kamu datang.
🧪 Tebakan cepat: Halaman daftar buku menampilkan judul dan nama penulis untuk tiga buku. Dengan REST butuh berapa request, dengan GraphQL berapa? Dan mana yang menerima byte lebih sedikit? Jawabannya ada di bagian "Diukur: halaman daftar buku".
Bedanya dalam satu tabel
| REST | GraphQL | |
|---|---|---|
| Alamat | satu URL per resource: /books/1, /authors/1 |
satu endpoint: /graphql |
| Bentuk response | ditentukan server | ditentukan query dari client |
| Method HTTP | GET, POST, PUT, PATCH, DELETE sesuai aksinya | biasanya POST untuk semua; query boleh lewat GET |
| Cache HTTP (browser, CDN) | GET per URL langsung bisa di-cache | POST gak di-cache |
| Status code | menunjukkan hasilnya: 200, 404, 422 | sering 200 walaupun ada errors |
| Daftar field | dibaca dari dokumentasi | tertulis di schema |
Contohnya tetap Toko Buku dari pelajaran sebelumnya: REST di https://api.tokobuku.test/books/1, GraphQL di https://api.tokobuku.test/graphql. Semua angka byte di bawah adalah body JSON saja, tanpa header HTTP. RTT (round-trip time) adalah waktu satu kali bolak-balik ke server. Di sini dipakai 100 ms, angka yang wajar di jaringan seluler.
Diukur: halaman detail buku
Halaman detail butuh judul, harga, dan nama penulis Laskar Pelangi.
| REST | GraphQL | |
|---|---|---|
| Request | 2, berurutan (/books/1 lalu /authors/1) |
1 |
| Body yang dikirim | 0 byte (GET gak punya body) | 59 byte |
| Body yang diterima | 72 + 31 = 103 byte | 92 byte |
| Waktu tunggu jaringan (RTT 100 ms) | 200 ms | 100 ms |
Jujur saja: untuk satu buku, total byte-nya gak beda jauh, bahkan GraphQL lebih banyak kalau body yang dikirim ikut dihitung (59 + 92 = 151 byte lawan 103 byte). Yang pasti menang adalah jumlah bolak-baliknya: satu, bukan dua.
Diukur: halaman daftar buku
REST harus mengambil daftar buku dulu, baru tahu penulis mana yang perlu diminta:
GET /books → 3 buku, 219 byte
GET /authors/1 → 31 byte
GET /authors/2 → 39 byte
GET /authors/3 → 31 byte
GraphQL cukup satu query, body-nya 47 byte:
{ books { title author { name } } }
| REST | GraphQL | |
|---|---|---|
| Request | 4 | 1 |
| Putaran bolak-balik | 2 (3 request penulis dikirim bareng) | 1 |
| Body yang diterima | 219 + 31 + 39 + 31 = 320 byte | 210 byte |
| Waktu tunggu jaringan (RTT 100 ms) | 200 ms | 100 ms |
Itu jawaban tebakannya: REST 4 request, GraphQL 1, dan GraphQL menerima 110 byte lebih sedikit, karena /books ikut mengirim id, author_id, price, dan stock yang gak dipakai. Selisihnya membesar kalau datanya banyak: 20 buku dengan 20 penulis berbeda berarti 21 request REST, GraphQL tetap 1.
Cache HTTP: di sini REST unggul
Response GET /books/1 bisa diberi header Cache-Control: max-age=60. Selama 60 detik berikutnya, browser menjawab dari cache-nya sendiri: kunjungan kedua ke halaman detail itu 0 request. CDN juga bisa menyimpan URL yang sama untuk semua pengunjung.
GraphQL lewat POST gak dapat itu. Browser dan CDN pada praktiknya gak menyimpan response POST, jadi kunjungan kedua tetap 1 request ke server. Ada dua jalan keluar:
- Kirim query lewat GET:
https://api.tokobuku.test/graphql?query=%7B+book%28id%3A+1%29+.... Response-nya bisa di-cache seperti REST, tapi URL-nya panjang dan tiap query yang beda sedikit jadi URL yang beda. Mutation gak boleh lewat GET. - Pakai cache di client, seperti cache bawaan Apollo Client. Itu menyimpan data di memori aplikasi, bukan di cache HTTP, jadi gak dipakai bareng CDN dan hilang saat halaman di-refresh.
Status code: 404 lawan 200
Di REST, GET /books/99 dijawab 404 Not Found. Status code-nya sudah cerita. Di GraphQL, book(id: 99) menghasilkan data: { book: null } plus errors, dan status HTTP-nya tergantung server:
| Kasus | Apollo Server | Draft GraphQL over HTTP |
|---|---|---|
Data lengkap, tanpa errors |
200 | 200 |
book(id: 99): ada data dan errors |
200 | 294 |
Gagal di-parse: { book(id: 1) { |
400 | 400 |
Gagal validasi: field isbn |
400 | 422 |
| Mutation dikirim lewat GET | 405 | 405 |
Draft GraphQL over HTTP adalah spesifikasi yang sedang disusun untuk aturan HTTP-nya. Kode 294 (Partial Success) di situ kode baru untuk "data ada, tapi ada error juga". Kode ini belum terdaftar resmi, jadi client yang gak mengenalnya memperlakukannya seperti 200. Banyak server yang dipakai sekarang menjawab 200 untuk kasus itu. Kesimpulannya: di GraphQL, status 200 belum tentu sukses. Baca errors di body.
Kapan REST, kapan GraphQL
REST lebih cocok ketika caching HTTP penting dan API-nya relatif sederhana: katalog publik yang dibaca jutaan kali lewat CDN, CRUD dengan resource yang jelas, API publik yang cukup dicoba pakai curl, atau upload dan download file besar.
GraphQL lebih cocok ketika banyak tampilan butuh field yang berbeda dari data yang sama (web, aplikasi mobile), datanya bersarang (buku → penulis → buku lain), RTT-nya tinggi sehingga tiap bolak-balik terasa, atau satu pintu masuk di depan banyak layanan.
Banyak perusahaan memakai keduanya: REST untuk API publik, GraphQL untuk aplikasi mereka sendiri.
⚠️ Jebakan yang sering ketemu
- Menganggap GraphQL selalu lebih cepat. Untuk satu resource yang di-cache, REST bisa 0 request, GraphQL lewat POST tetap 1.
- Cuma mengecek
response.ok. Di banyak server,book(id: 99)datang dengan status 200, jadiresponse.okbernilaitrue, padahaldata.bookbernilainull. Cekerrors. - Mengirim mutation lewat GET. Ditolak dengan 405. GET cuma untuk query.
- Mengira masalah request berantai hilang begitu saja. Client cuma mengirim 1 request, tapi server bisa saja tetap membaca database sekali per buku untuk mencari penulisnya. Itu dibahas di pelajaran "N+1 Problem & DataLoader".
🤔 Bagaimana dengan versi API?
REST biasanya membuat versi baru di URL (/v1/books, /v2/books) saat bentuk response berubah. GraphQL biasanya punya satu schema yang terus berkembang: field baru boleh ditambah kapan saja tanpa mengganggu client lama, karena client cuma menerima field yang dia minta. Field lama ditandai @deprecated, lalu dihapus setelah gak ada client yang memakainya.
TL;DR: REST punya banyak endpoint dengan bentuk response dari server. GraphQL punya satu endpoint dan bentuk response dari query client. Diukur di Toko Buku: halaman detail 2 request REST (103 byte) lawan 1 query (92 byte), halaman daftar 4 request (320 byte) lawan 1 query (210 byte); yang pasti menang adalah jumlah bolak-balik, bukan selalu byte. REST unggul di cache HTTP: GET per URL bisa disimpan browser dan CDN, sedangkan GraphQL lewat POST tetap 1 request tiap kali. Status code GraphQL tergantung server (Apollo: 200 untuk data dan errors, 400 untuk query yang gagal di-parse atau gagal validasi; draft GraphQL over HTTP: 294 dan 422), jadi selalu baca errors. Pilih REST untuk API sederhana yang butuh caching HTTP, GraphQL untuk data bersarang dan client dengan kebutuhan field yang beda-beda.