- Dalam rekayasa perangkat lunak, API adalah alat inti, dan API yang baik sebaiknya terasa familier dan sederhana sampai-sampai membosankan
- Karena API sulit diubah setelah dipublikasikan, prinsip tidak merusak lingkungan pengguna (WE DO NOT BREAK USERSPACE) sangat penting
- Jika perubahan tak terhindarkan, versioning diperlukan, tetapi ini adalah kejahatan yang perlu karena sangat meningkatkan kompleksitas dan biaya pemeliharaan
- Pada akhirnya, kualitas API bergantung pada nilai produk itu sendiri, dan produk yang dirancang buruk akan menyulitkan pembuatan API yang baik
- Demi stabilitas dan skalabilitas, perlu mempertimbangkan autentikasi berbasis API key, idempotensi, rate limit, dan pagination berbasis cursor
Pendahuluan: pentingnya dan konteks desain API
- Salah satu pekerjaan utama insinyur perangkat lunak modern adalah berinteraksi dengan API
- Penulis juga memiliki pengalaman merancang/mengimplementasikan/memanfaatkan API publik dan internal dalam berbagai bentuk seperti REST, GraphQL, dan alat command line
- Saran desain API yang ada saat ini cenderung terobsesi pada konsep yang rumit (definisi REST, HATEOAS, dan sebagainya)
- Tulisan ini merangkum prinsip desain API yang praktis berdasarkan pengalaman nyata
Keseimbangan antara keakraban dan fleksibilitas: syarat pertama API yang baik
- API yang baik adalah API yang 'biasa dan membosankan', yaitu cara pakainya harus mirip dengan API lain yang sudah pernah ditemui
- Karena pengguna lebih fokus pada pencapaian tujuan mereka daripada API itu sendiri, desain dengan hambatan masuk rendah sangat diperlukan
- API yang sudah dipublikasikan sangat sulit diubah, sehingga kehati-hatian diperlukan sejak tahap desain awal
- Pengembang selalu menginginkan API yang sesederhana mungkin, tetapi tetap harus memikirkan fleksibilitas jangka panjang
- Pada akhirnya, keseimbangan antara keakraban dan fleksibilitas jangka panjang adalah tantangan utamanya
Jangan pernah merusak userspace (WE DO NOT BREAK USERSPACE)
- Perubahan berupa penambahan field pada struktur respons biasanya tidak masalah
- Namun penghapusan field, perubahan tipe, atau perubahan struktur akan merusak kode semua konsumen
- Pemelihara API memiliki tanggung jawab untuk tidak dengan sengaja merusak perangkat lunak pengguna lama
- Bahkan alasan typo pada header HTTP "referer" tidak diperbaiki pun adalah karena budaya menjaga userspace
Mengubah API tanpa merusaknya: strategi versioning
- Perubahan yang breaking pada API hanya boleh dilakukan jika benar-benar perlu, dan dalam situasi itu versioning adalah jawabannya
- Versi lama dan versi baru harus dioperasikan secara bersamaan sambil mendorong transisi bertahap
- Identifier versi bisa diterapkan dengan berbagai cara seperti URL(
/v1/) atau header, sehingga pengguna dapat bermigrasi sesuai kecepatannya masing-masing
- Versioning memiliki kelemahan berupa biaya pemeliharaan yang sangat besar (endpoint bertambah, testing, support) dan kebingungan pengguna
- Bahkan jika seperti Stripe ada lapisan translasi internal, kompleksitas dasarnya tetap tidak bisa dihindari
- Penerapan versioning API harus menjadi pilihan terakhir
Faktor keberhasilan API sepenuhnya bergantung pada nilai produk
- API pada dasarnya hanyalah antarmuka dari produk bisnis yang nyata
- API seperti OpenAI dan Twilio pun pada akhirnya dicari pengguna karena fungsi yang disediakan API itu sendiri
- Jika produknya bernilai, orang akan tetap menggunakannya meski API-nya kurang nyaman
- Kualitas API adalah karakteristik "margin": ia baru menjadi faktor pembeda ketika daya saing intinya mirip
- Sebaliknya, produk yang sama sekali tidak punya API adalah hambatan besar bagi pengguna teknis
Jika desain produk buruk, API juga tidak bisa menjadi baik
- Meski ada API yang matang secara teknis, itu tidak berarti jika produknya tidak laku di pasar
- Yang lebih penting, jika struktur resource dasarnya tidak logis atau tidak efisien, hal itu akan terlihat juga di API
- Misalnya, sistem yang menyimpan komentar sebagai linked list akan membuat desain RESTful sekalipun sulit muncul secara alami
- Masalah teknis yang bisa disembunyikan di UI akan terekspos semuanya di API, dan ini memaksa pengguna memahami sistem secara tidak perlu
Autentikasi (Authenticaton) dan keragaman pengguna
- Dukungan untuk autentikasi berbasis API key berumur panjang harus disediakan
- Walaupun metode yang lebih aman seperti OAuth juga didukung, hambatan masuk API key jauh lebih rendah
- Konsumen API bukan hanya engineer, tetapi juga non-developer (sales, perencana, pelajar, pengembang hobi, dan lain-lain)
- Persyaratan autentikasi yang sulit atau rumit (seperti OAuth) menjadi hambatan bagi pengguna nonspesialis
Idempotensi dan penanganan retry
- Untuk request yang bersifat aksi (misalnya pembayaran, perubahan status, dan sebagainya), keamanan terhadap retry saat gagal sangat penting
- Idempotensi berarti menjamin bahwa hasil hanya diproses sekali walaupun request yang sama dikirim berkali-kali
- Cara standarnya adalah mencegah pemrosesan duplikat dengan mengirimkan "idempotency key" melalui parameter atau header
- Penyimpanan idempotency key cukup menggunakan penyimpanan key/value sederhana seperti Redis, dan dalam banyak kasus penerapan masa kedaluwarsa berkala tidak masalah
- Untuk request baca/hapus (gaya REST), ini umumnya tidak diperlukan
Keamanan API dan rate limiting
- Request API melalui kode dapat terjadi jauh lebih cepat daripada interaksi manual pengguna
- Satu API yang dirilis tanpa banyak pikir bisa dimanfaatkan dengan cara tak terduga (misalnya sistem chat skala besar)
- Rate limit wajib ada, dan harus diterapkan lebih ketat pada operasi yang biayanya tinggi
- Opsi menonaktifkan API sementara untuk pelanggan tertentu (
killswitch) juga patut dipertimbangkan
- Informasi rate limit perlu disampaikan lewat header respons seperti
X-Limit-Remaining, Retry-After, dan sebagainya
Strategi pagination
- Untuk mengembalikan dataset besar secara efisien (misalnya jutaan tiket), pagination itu wajib
- Pagination berbasis offset (Offset-based) sederhana, tetapi pada data besar akan makin lambat
- Pagination berbasis cursor (Cursor-based) efektif bahkan untuk dataset yang sangat besar tanpa penurunan performa query
- Pendekatan berbasis cursor memang agak lebih sulit diimplementasikan dan digunakan, tetapi dalam jangka panjang kemungkinan besar akan menjadi perubahan yang esensial
- Menyertakan field seperti
next_page dalam respons agar cursor untuk request berikutnya jelas adalah pilihan yang bijak
Field opsional dan pandangan tentang GraphQL
- Field yang mahal atau lambat sebaiknya dikeluarkan dari respons default dan hanya ditambahkan secara opsional saat diperlukan
- Data terkait bisa disertakan melalui parameter seperti
includes
- GraphQL punya keunggulan dalam fleksibilitas struktur data, tetapi juga memiliki masalah seperti aksesibilitas yang lebih rendah bagi non-developer, caching/edge case yang makin rumit, dan kesulitan implementasi di backend
- Berdasarkan pengalaman praktik, penerapan GraphQL sebaiknya dibatasi pada kasus yang benar-benar perlu
Karakteristik API internal
- API internal perusahaan memiliki banyak kondisi yang berbeda dari API eksternal (API yang dipublikasikan)
- Karena konsumennya kebanyakan adalah insinyur perangkat lunak profesional, autentikasi yang lebih kompleks atau perubahan breaking bisa lebih dimungkinkan
- Meski begitu, prinsip desain untuk idempotensi, pencegahan insiden, dan meminimalkan beban operasional tetap berlaku
Ringkasan
- API sulit diubah dan harus mudah digunakan
- Tidak merusak userspace adalah kewajiban paling penting bagi pemelihara API
- Versioning API mahal biayanya sehingga hanya boleh dipakai sebagai pilihan terakhir
- Pada akhirnya, kualitas API ditentukan oleh nilai esensial dari produknya
- Produk yang dirancang buruk memiliki keterbatasan besar meski sudah dicoba ditambal di level API
- Dukungan autentikasi sederhana, idempotensi untuk request aksi yang penting, serta rate limit/pagination dan langkah stabilitas lainnya sangat krusial
- API internal memiliki strategi yang berbeda tergantung tujuan dan penggunanya, tetapi tetap membutuhkan kehati-hatian dalam desain
- REST, JSON, OpenAPI, dan format sejenis bukanlah isu yang paling esensial; dokumentasi yang jelas jauh lebih penting
Belum ada komentar.