API versioning adalah cara mengubah API tanpa merusak client yang sudah memakainya. Bayangin toko yang ganti nomor telepon. Toko yang baik gak langsung mematikan nomor lama. Nomor lama tetap aktif beberapa bulan dengan pesan "nomor ini berhenti 1 April, simpan nomor baru", baru setelah itu dimatikan. Sebaliknya, menambah nomor WhatsApp gak mengganggu siapa pun: yang lama tetap jalan.
🧪 Tebakan cepat: di satu rilis, kamu menambah field
currency: "IDR"ke jawabanGET /books/1, dan menggantipricedari angka89000jadi teks"89000". Mana yang merusak aplikasi lama? Tebak dulu, jawabannya ada di bagian "Breaking change atau aman?".
Breaking change atau aman?
Aplikasi Toko Buku versi lama sudah terpasang di ribuan HP dan gak bisa kamu ubah. Kodenya ditulis untuk jawaban v1 {"id": 1, "title": "Laskar Pelangi", "author_id": 1, "price": 89000, "stock": 12}:
function renderBook(book) {
const harga = "Rp " + book.price.toLocaleString("id-ID");
const total = book.price + 10000; // + ongkir
const status = book.stock > 0 ? "tersedia" : "habis";
return book.title + " | " + harga + " | total " + total + " | " + status;
}
Dengan v1, hasilnya Laskar Pelangi | Rp 89.000 | total 99000 | tersedia. Sekarang jalankan kode yang sama pada jawaban yang sudah diubah:
| Perubahan | Hasil di aplikasi lama | Jenis |
|---|---|---|
tambah "currency": "IDR" |
Laskar Pelangi | Rp 89.000 | total 99000 | tersedia |
aman |
price jadi "89000" |
Laskar Pelangi | Rp 89000 | total 8900010000 | tersedia |
breaking |
title diganti name |
undefined | Rp 89.000 | total 99000 | tersedia |
breaking |
stock diganti in_stock: true |
Laskar Pelangi | Rp 89.000 | total 99000 | habis |
breaking |
POST /books wajib isbn |
request lama dijawab 422 |
breaking |
Menambah currency aman, karena kode lama gak pernah membacanya. Mengganti price jadi teks yang merusak: "89000" + 10000 di JavaScript menyambung teks jadi "8900010000". Itu jawaban tebakannya.
Aturannya:
- Aman (non-breaking): menambah field baru di jawaban, menambah endpoint baru, menambah parameter yang opsional.
- Breaking change: menghapus atau mengganti nama field, mengubah tipe datanya, mewajibkan input baru, mengubah arti status atau format. Client yang sudah ada jadi error, atau lebih buruk: diam-diam menampilkan data yang salah.
Breaking change gak boleh dirilis di versi yang sama. Ia butuh versi baru.
Tiga cara menulis versi
| Cara | Request client v2 | Catatan |
|---|---|---|
| URL | GET /v2/books/1 |
paling populer: jelas, gampang di-cache dan di-route, bisa dicoba di browser |
| Header | GET /books/1 + Api-Version: 2 |
URL tetap bersih; jawabannya wajib Vary: Api-Version supaya cache gak tertukar |
| Media type | GET /books/1 + Accept: application/vnd.tokobuku.v2+json |
versi menempel di format; perlu Vary: Accept |
Query parameter (/books/1?version=2) juga dipakai, tapi gampang terlupa. Untuk header dan media type, client yang gak mengirim versi harus tetap dapat v1, karena aplikasi lama gak tahu header itu.
v1 dan v2 berdampingan
Versi lama tetap dijawab persis seperti dulu, dan bentuk baru tinggal di versi baru:
app.get("/v1/books/:id", (req, res) => {
const book = books.find((b) => b.id === Number(req.params.id));
res.json({ id: book.id, title: book.title, author_id: book.author_id, price: book.price, stock: book.stock });
});
app.get("/v2/books/:id", (req, res) => {
const book = books.find((b) => b.id === Number(req.params.id));
res.json({ id: book.id, name: book.title, author_id: book.author_id, price: book.price, in_stock: book.stock > 0 });
});
- Datanya satu (
books); yang berbeda cuma bentuk jawabannya. - Aplikasi lama tetap memanggil
/v1/...dan tetap jalan. - Aplikasi baru memanggil
/v2/...dan mendapat bentuk baru.
Latihan memakai pola yang sama untuk users. v1 menjawab [{"name": "Budi"}], v2 membungkus data dan mengganti nama field-nya:
app.get("/api/v1/users", (req, res) => {
res.json([{ name: "Budi" }]);
});
app.get("/api/v2/users", (req, res) => {
res.json({ data: [{ full_name: "Budi", registered: true }], version: 2 });
});
Mengumumkan pensiun: Deprecation dan Sunset
Versi lama gak hidup selamanya, tapi dimatikan dengan pemberitahuan. Jawaban v1 mulai membawa header:
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: @1790812800
Sunset: Thu, 01 Apr 2027 00:00:00 GMT
Link: <https://api.tokobuku.test/docs/migrasi-v2>; rel="deprecation"
Deprecation(RFC 9745): sejak kapan versi ini gak disarankan, dalam detik Unix.@1790812800artinya 1 Oktober 2026.Sunset(RFC 8594): kapan versi ini berhenti menjawab.Linkdenganrel="deprecation"menunjuk panduan migrasinya.
Urutannya: umumkan jauh-jauh hari (6 sampai 12 bulan), pasang header-nya, tulis panduan migrasi, pantau siapa yang masih memanggil v1, lalu matikan setelah tanggal Sunset (misalnya menjawab 410 Gone).
🤔 Nomor versi: semantic versioning
Nomor seperti v2.3.1 dibaca MAJOR.MINOR.PATCH:
2adalah major version: naik saat ada breaking change.3adalah minor: fitur baru yang aman, misalnya field baru.1adalah patch: perbaikan bug.
URL API biasanya cuma membawa major (/v2), karena minor dan patch gak merusak siapa pun.
⚠️ Jebakan yang sering ketemu
- Menghapus field di versi yang sudah dirilis. Itu breaking change: client yang membacanya jadi error. Tambahkan field baru, jangan hapus yang lama.
- Mengubah tipe data diam-diam. Angka jadi teks gak bikin error, tapi bikin hitungan salah, dan itu lebih susah ketahuan.
- Default versi ikut naik. Kalau request tanpa versi tiba-tiba dapat v2, semua aplikasi lama rusak sekaligus.
- Mematikan v1 tanpa pemberitahuan. Pasang
DeprecationdanSunsetdulu, dan beri waktu.
TL;DR: Perubahan yang aman: menambah field, endpoint, atau parameter opsional. Breaking change: menghapus atau mengganti nama field, mengubah tipenya, mewajibkan input baru; itu butuh versi baru. Versi ditulis di URL (/v1/books, paling populer), di header (Api-Version: 2, plus Vary), atau di media type (Accept: application/vnd.tokobuku.v2+json), dan request tanpa versi tetap v1. v1 dan v2 berjalan berdampingan dari data yang sama. Versi lama dipensiunkan dengan Deprecation, Sunset, dan panduan migrasi. Di v2.3.1, 2 adalah major version, yang naik saat ada breaking change.