Content Negotiation: Tawar-menawar Format Data
Memahami cara klien dan server menyepakati format, bahasa, dan encoding lewat header Accept.
Pelayan yang bertanya sebelum menyajikan
Kamu masuk restoran internasional. Pelayan bertanya: "mau menu bahasa Indonesia atau Inggris? Mau porsi besar atau kecil?" Baru setelah kamu jawab, ia mengambilkan yang sesuai. Content negotiation adalah "tanya jawab" versi HTTP: klien memberitahu preferensinya lewat header Accept-*, server memilih representasi terbaik yang ia bisa berikan.
Kenapa negosiasi ini ada
Satu URL bisa menyajikan banyak versi: JSON untuk aplikasi, HTML untuk browser, bahasa Indonesia untuk user lokal, Inggris untuk user luar. Tanpa negosiasi, server harus menebak atau membuat URL terpisah untuk setiap kombinasi. Dengan negosiasi, satu endpoint melayani semua klien dengan cerdas.
Contoh 1: negosiasi format
GET /api/produk/1 HTTP/1.1
Host: toko.contoh.id
Accept: application/jsonHTTP/1.1 200 OK
Content-Type: application/json
{"id": 1, "nama": "Kopi Tubruk"}Browser yang membuka URL sama mengirim Accept: text/html, dan server bisa menjawab halaman HTML. Satu URL, dua wajah. Klien juga bisa memberi bobot preferensi:
Accept: application/json, text/html;q=0.8Artinya: "saya mau JSON, tapi HTML juga boleh (prioritas 0.8)."
Contoh 2: negosiasi bahasa dan encoding
GET /tentang HTTP/1.1
Host: toko.contoh.id
Accept-Language: id, en;q=0.7
Accept-Encoding: gzip, brServer menjawab halaman bahasa Indonesia (karena id prioritas tertinggi) yang dikompresi gzip. Kalau server tidak bisa memenuhi bahasa yang diminta, ia memakai bahasa default, bukan error. Hanya kalau tidak ada format yang cocok sama sekali server menjawab 406 Not Acceptable, yang dalam praktik jarang dipakai.
Kesalahan umum
Salah: mengabaikan Accept dan selalu mengirim JSON. Untuk API publik tidak masalah, tapi untuk konten multi-format ini membuang fitur HTTP. Yang benar: baca header Accept kalau API-mu melayani banyak klien.
Salah: tidak menangani q-value. Mengambil bahasa pertama tanpa memperhatikan bobot. Yang benar: parse q-value, atau pakai library negosiasi yang sudah ada.
Salah: lupa Vary saat response berbeda per header. Cache bisa menyajikan versi bahasa Inggris ke user Indonesia. Yang benar: sertakan Vary: Accept-Language agar cache membedakan.
Contoh nyata: GitHub API
GitHub API memakai negosiasi versi lewat header Accept:
Accept: application/vnd.github.v3+jsonSatu URL api.github.com/users/octocat bisa mengembalikan format v3 atau format lain tergantung header ini. Klien lama yang tidak mengirim header mendapat versi default. Ini contoh elegan: URL stabil, perilaku berubah lewat negosiasi.
Untuk API-mu sendiri, pola sederhana yang cukup: selalu JSON, dan bahasa lewat query ?lang=id. Negosiasi penuh (q-value, 406) baru dibutuhkan untuk API publik yang kompleks.
Catatan teknis: Di praktik API modern, negosiasi format sering disederhanakan: JSON selalu, bahasa diatur lewat path (
/id/produk) atau query. Tapi memahami mekanisme aslinya membantumu membaca dokumentasi API mana pun.
Tantangan
Tebak respons dari header Accept
Server bisa menyajikan JSON dan HTML untuk /info. Tentukan respons untuk tiap request:
- Accept: application/json
- Accept: text/html
- Accept: application/xml (server tidak mendukung XML)
Tulis: request -> Content-Type respons (atau status error).