paginationapi-designperformaMenengah3 mnt baca

Cursor Pagination: Pagination untuk Data yang Terus Berubah

Memahami keterbatasan offset pagination dan cara kerja cursor-based pagination untuk feed real-time.

Nomor halaman vs penanda buku

Membaca buku cetak, kamu pakai nomor halaman (offset): "lanjut halaman 42". Tapi feed media sosial tidak punya nomor halaman yang stabil: saat kamu scroll, postingan baru terus muncul di atas dan menggeser semuanya. Solusinya seperti penanda buku: "lanjutkan dari postingan terakhir yang saya lihat." Itulah cursor pagination.

Kenapa offset gagal untuk data dinamis

Offset (?page=3&limit=10) berarti "lewati 20 item pertama". Kalau 5 item baru muncul sebelum user pindah halaman, item yang tadinya di posisi 21-30 bergeser ke 26-35: user melihat 5 item yang sama dua kali dan melewatkan 5 item lain. Untuk katalog yang jarang berubah ini tidak masalah; untuk feed, notifikasi, atau riwayat transaksi yang hidup, ini bug nyata.

Contoh 1: request dan response cursor

http
GET /api/feed?limit=10&cursor=eyJpZCI6OTUwfQ== HTTP/1.1
Host: toko.contoh.id
json
{
  "data": ["...10 postingan..."],
  "next_cursor": "eyJpZCI6OTQwfQ==",
  "has_more": true
}

Cursor adalah penanda buram (biasanya id atau timestamp ter-encode) yang berarti "lanjutkan setelah item ini". Server mengambil item setelah cursor, mengembalikan cursor baru untuk halaman berikutnya. Item baru yang muncul di atas tidak menggeser apa pun.

Contoh 2: kapan pakai yang mana

javascript
// Katalog produk (jarang berubah): offset cukup
await fetch("/api/produk?page=2&limit=20");

// Feed notifikasi (terus bertambah): cursor wajib
let cursor = null;
async function muatLagi() {
  const url = "/api/notifikasi?limit=10" + (cursor ? "&cursor=" + cursor : "");
  const res = await fetch(url).then(r => r.json());
  tampilkan(res.data);
  cursor = res.next_cursor;
}

Aturan praktis: butuh "lompat ke halaman 7"? Pakai offset. Data bertambah terus dan user scroll berurutan? Pakai cursor.

Kesalahan umum

Salah: memaksa offset untuk feed real-time. Duplikasi dan item terlewat. Yang benar: cursor untuk data dinamis.

Salah: membuat cursor bisa ditebak/dimodifikasi. Cursor ?cursor=100 memungkinkan user melompat sembarang dan mengintip. Yang benar: encode dan tanda tangani cursor, atau validasi di server.

Salah: tidak menangani cursor kedaluwarsa. Item acuan sudah dihapus, cursor tidak valid. Yang benar: fallback elegan (mulai dari awal) dengan pesan yang jelas.

Contoh cursor paling sederhana

Cursor tidak harus rumit. Untuk data ber-id urut, id terakhir cukup:

javascript
// Server: ambil 10 item setelah id tertentu
const items = await db.notifikasi
  .where("id", "<", cursorTerakhir)
  .orderBy("id", "desc")
  .limit(10);

// Response
{ "data": items, "next_cursor": items[items.length-1].id }

Klien menyimpan next_cursor dan mengirimnya di request berikutnya. Tidak perlu encode rumit untuk kasus internal. Yang penting: cursor menunjuk ITEM, bukan posisi angka.

Catatan teknis: API besar seperti Twitter/X, Facebook, dan Stripe memakai cursor pagination. Kalau kamu membangun feed atau timeline, ikuti pola mereka sejak awal daripada migrasi belakangan.

Tantangan

Buktikan bug offset pagination

Simulasikan dengan array JavaScript:

  1. Buat array 30 angka (1-30). Ambil "halaman 2" dengan offset: lewati 10, ambil 10.
  2. Sekarang unshift 5 angka baru di depan (simulasi data baru), lalu ambil "halaman 3" dengan offset yang sama.
  3. Tulis item mana yang duplikat/terlewat, dan jelaskan kenapa cursor menghindari ini.

Tulis sebagai kode + 2 baris penjelasan.