Suatu kali saya membantu seorang teman yang perlu mengintegrasikan data tentang perumahan yang bebas dan ditempati dari sistem manajemen properti dengan situs kliennya. Saya senang, sistem ini memiliki API. Tapi, sayangnya, itu diatur dengan sangat buruk.
Saya memutuskan untuk menulis artikel ini bukan untuk mengkritik sistem yang akan dibahas, tetapi untuk berbicara tentang kesalahan apa yang terjadi selama pengembangan API, dan menyarankan cara untuk memperbaiki kesalahan ini.
Tinjauan situasi
Organisasi tersebut menggunakan sistem
Beds24 untuk mengelola ruang tamu. Informasi tentang apa yang gratis dan yang sibuk disinkronkan dengan berbagai sistem reservasi untuk akomodasi (seperti Pemesanan, AirBnB, dan lainnya). Organisasi ini terlibat dalam pengembangan situs dan ingin pencarian hanya menampilkan informasi tentang kamar yang tersedia untuk jangka waktu tertentu dan kapasitas yang sesuai. Tugas ini tampak sangat sederhana, karena Beds24 menyediakan API untuk integrasi dengan sistem lain. Bahkan, ternyata para pengembang API ini membuat banyak kesalahan dalam desainnya. Saya mengusulkan untuk mengurai kesalahan-kesalahan ini, mengidentifikasi masalah-masalah spesifik dan berbicara tentang bagaimana mendekati pengembangan API dalam situasi yang sedang dipertimbangkan.
Masalah # 1: format permintaan tubuh
Karena klien hanya tertarik pada informasi tentang apakah, katakanlah, kamar hotel gratis atau sibuk, kami hanya tertarik merujuk pada
/getAvailabilities
API
/getAvailabilities
. Dan, meskipun panggilan ke API semacam itu harus mengarah ke data tentang ketersediaan kamar, panggilan ini, pada kenyataannya, tampak seperti permintaan POST, karena penulis API memutuskan untuk melengkapinya dengan kemampuan untuk menerima filter sebagai badan permintaan JSON. Berikut adalah daftar parameter kueri dan contoh nilai yang mungkin mereka terima:
{ "checkIn": "20151001", "lastNight": "20151002", "checkOut": "20151003", "roomId": "12345", "propId": "1234", "ownerId": "123", "numAdult": "2", "numChild": "0", "offerId": "1", "voucherCode": "", "referer": "", "agent": "", "ignoreAvail": false, "propIds": [ 1235, 1236 ], "roomIds": [ 12347, 12348, 12349 ] }
Mari kita berjalan melalui objek JSON ini dan berbicara tentang apa yang salah di sini.
- Tanggal (
checkIn
, lastNight
dan checkOut
) dalam format YYYYMMDD
. Sama sekali tidak ada alasan untuk tidak menggunakan format standar ISO 8601 ( YYYY-MM-DD
) ketika mengonversi tanggal menjadi string, karena ini adalah standar yang banyak digunakan untuk menyajikan tanggal. Ini akrab bagi banyak pengembang, itu adalah apa yang diharapkan banyak parser JSON untuk menerima pada input. Selain itu, ada perasaan bahwa bidang lastNight
berlebihan, karena ada bidang checkOut
, yang selalu diwakili oleh tanggal satu hari sebelum tanggal yang ditentukan dalam lastNight
. Sehubungan dengan kekurangan yang disebutkan di atas, saya mengusulkan, ketika merancang API tersebut, untuk berusaha untuk selalu menggunakan metode standar untuk menyajikan tanggal dan mencoba untuk tidak membebani pengguna API dengan kebutuhan untuk bekerja dengan data yang berlebihan. - Semua bidang pengidentifikasi, serta bidang
numAdult
dan numChild
, berupa angka, tetapi direpresentasikan sebagai string. Dalam hal ini, tidak ada alasan yang jelas untuk mewakili mereka sebagai string. - Di sini Anda dapat melihat pasangan bidang berikut:
roomId
dan roomIds
, serta propId
dan propIds
. Kehadiran bidang roomId
dan propId
berlebihan, karena keduanya dapat digunakan untuk mengirimkan pengidentifikasi. Selain itu, ada masalah dengan tipe. Harap dicatat bahwa bidang roomId
adalah bidang string, dan nilai numerik pengidentifikasi harus digunakan dalam array roomIds
. Ini dapat menyebabkan kebingungan, masalah dengan penguraian, dan, di samping itu, menunjukkan bahwa pada server beberapa operasi dilakukan dengan string, dan beberapa dengan angka, meskipun fakta bahwa string dan angka ini digunakan untuk mewakili yang sama data.
Saya ingin mengundang pengembang API untuk mencoba tidak menyulitkan kehidupan mereka yang akan menggunakan API ini, sambil membuat kesalahan seperti API saat merancang API. Yaitu, perlu berjuang untuk pemformatan data standar, untuk memastikan bahwa mereka tidak berlebihan, untuk memastikan bahwa berbagai jenis data tidak digunakan untuk mewakili entitas yang homogen. Dan itu tidak layak untuk semuanya, tanpa pandang bulu, untuk disajikan dalam bentuk garis.
Masalah # 2: format badan respons
Seperti yang telah disebutkan, kami hanya tertarik pada
/getAvailabilities
API
/getAvailabilities
. Mari kita lihat seperti apa jawaban dari titik akhir ini dan berbicara tentang apa kekurangan yang dibuat selama pembentukannya. Ingatlah bahwa ketika mengakses API, kami tertarik pada daftar pengidentifikasi objek yang gratis untuk jangka waktu tertentu dan dapat mengakomodasi sejumlah orang. Di bawah ini adalah contoh isi permintaan untuk API dan contoh dari apa yang dikembalikan sebagai tanggapan atas permintaan ini.
Ini permintaannya:
{ "checkIn": "20190501", "checkOut": "20190503", "ownerId": "25748", "numAdult": "2", "numChild": "0" }
Inilah jawabannya:
{ "10328": { "roomId": "10328", "propId": "4478", "roomsavail": "0" }, "13219": { "roomId": "13219", "propId": "5729", "roomsavail": "0" }, "14900": { "roomId": "14900", "propId": "6779", "roomsavail": 1 }, "checkIn": "20190501", "lastNight": "20190502", "checkOut": "20190503", "ownerId": 25748, "numAdult": 2 }
Bicara tentang masalah respons.
- Di badan respons, properti
ownerId
dan numAdult
tiba-tiba menjadi angka. Dan dalam permintaan itu perlu untuk menunjukkan mereka dalam bentuk string. - Daftar objek real estat disajikan dalam bentuk properti objek, kuncinya adalah pengidentifikasi ruang (
roomId
). Adalah logis untuk mengharapkan bahwa data tersebut akan dikeluarkan sebagai sebuah array. Bagi kami, ini berarti bahwa untuk mendapatkan daftar kamar yang tersedia, kita perlu roomsavail
ke seluruh objek, sambil memeriksa keberadaan properti tertentu dari objek yang terlampir di dalamnya, seperti roomsavail
, dan tidak memperhatikan sesuatu seperti checkIn
dan lastNight
. Maka akan perlu untuk memeriksa nilai properti kamar yang tersedia, dan jika lebih besar dari 0, kita dapat menyimpulkan bahwa properti yang sesuai tersedia untuk dipesan. Sekarang mari kita lihat properti kamar kamar. Berikut adalah opsi untuk mempresentasikannya di badan respons: "roomsavail": "0"
dan "roomsavail": 1
. Lihat polanya? Jika kamar ditempati, nilai properti diwakili oleh string. Jika gratis - itu berubah menjadi angka. Ini dapat menyebabkan banyak masalah dalam bahasa yang secara ketat terkait dengan tipe data, karena di dalamnya properti yang sama tidak boleh mengambil nilai dari tipe yang berbeda. Sehubungan dengan hal tersebut di atas, saya ingin menyarankan pengembang untuk menggunakan array objek JSON untuk mewakili set data tertentu, dan tidak menggunakan konstruksi yang tidak nyaman dalam bentuk pasangan nilai kunci yang serupa dengan yang kami pertimbangkan di sini. Selain itu, perlu untuk memastikan bahwa bidang objek yang homogen tidak berisi data dari jenis yang berbeda. Respons server yang diformat dengan benar mungkin terlihat seperti di bawah ini. Harap dicatat bahwa ketika menyajikan data dalam formulir ini, informasi kamar tidak mengandung data duplikat.
{ "properties": [ { "id": 4478, "rooms": [ { "id": 12328, "available": false } ] }, { "id": 5729, "rooms": [ { "id": 13219, "available": false } ] }, { "id": 6779, "rooms": [ { "id": 14900, "available": true } ] } ], "checkIn": "2019-05-01", "lastNight": "2019-05-02", "checkOut": "2019-05-03", "ownerId": 25748, "numAdult": 2 }
Masalah 3: penanganan kesalahan
Beginilah cara penanganan kesalahan diatur dalam API yang dipertimbangkan di sini: sistem mengirim respons dengan kode
200
ke semua permintaan, bahkan jika terjadi kesalahan. Ini berarti bahwa satu-satunya cara untuk membedakan respons normal dari respons dengan pesan kesalahan adalah dengan menguraikan isi respons dan memeriksa keberadaan bidang
error
atau
errorCode
error
di dalamnya. Hanya 6 kode kesalahan berikut disediakan di API.
Kode Kesalahan API Beds24Saya menyarankan agar setiap orang yang membaca ini mencoba untuk tidak mengembalikan respons dengan kode 200 (pemrosesan yang berhasil dari permintaan) jika terjadi kesalahan saat memproses permintaan. Anda dapat mengambil langkah ini hanya jika disediakan oleh kerangka kerja yang menjadi dasar Anda mengembangkan API. Mengembalikan kode respons yang memadai memungkinkan klien API untuk mengetahui terlebih dahulu tentang apakah mereka perlu mem-parsing badan respons atau tidak, dan bagaimana melakukannya (yaitu, apakah mem-parsing respons server normal atau objek kesalahan).
Dalam kasus kami, ada dua cara untuk meningkatkan API ke arah ini: Anda dapat memberikan kode HTTP khusus di kisaran 400-499 untuk masing-masing dari 6 kemungkinan kesalahan (yang terbaik untuk melakukannya), atau mengembalikan, jika terjadi kesalahan, kode 500, yang akan memungkinkan setidaknya, klien harus tahu sebelum menganalisis isi respons yang berisi informasi tentang kesalahan.
Masalah nomor 4: "instruksi"
Di bawah ini adalah "instruksi" untuk menggunakan API dari dokumentasi proyek:
Silakan baca instruksi berikut saat menggunakan API.
- Panggilan API harus dirancang sehingga selama pelaksanaannya harus mengirim dan menerima jumlah data minimum.
- Panggilan API dilakukan satu per satu. Anda harus menunggu hingga panggilan berikutnya ke API sebelum melakukan panggilan berikutnya.
- Jika Anda perlu melakukan beberapa panggilan ke API, jeda beberapa detik harus disediakan di antara mereka.
- Panggilan API tidak perlu dilakukan terlalu sering, mempertahankan tingkat panggilan pada tingkat minimum yang diperlukan untuk menyelesaikan tugas klien.
- Penggunaan API yang berlebihan dalam waktu 5 menit akan menyebabkan penangguhan akun Anda tanpa pemberitahuan tambahan.
- Kami berhak memblokir akses ke sistem untuk pelanggan yang, menurut pendapat kami, menggunakan API secara berlebihan. Ini dilakukan atas kebijakan kami dan tanpa pemberitahuan lebih lanjut.
Sementara poin 1 dan 4 terlihat cukup dibenarkan, saya tidak bisa setuju dengan poin lain dari instruksi ini. Pertimbangkan mereka.
- Item nomor 2. Jika Anda mengembangkan API REST, maka diasumsikan bahwa itu akan menjadi API yang independen terhadap negara. Kemandirian panggilan API dari panggilan sebelumnya adalah salah satu alasan mengapa teknologi REST telah menemukan aplikasi luas dalam aplikasi cloud. Jika modul tertentu dari sistem tidak mendukung keadaan, itu dapat dengan mudah digunakan kembali jika terjadi kesalahan. Sistem yang didasarkan pada modul-modul tersebut dengan mudah berskala ketika beban pada mereka berubah. Saat merancang API RESTful, Anda harus memastikan bahwa itu adalah API independen dan bahwa mereka yang menggunakannya tidak perlu khawatir tentang sesuatu seperti mengeksekusi hanya satu permintaan pada satu waktu.
- Item nomor 3. Item ini terlihat agak aneh dan ambigu. Saya tidak dapat memahami alasan mengapa paragraf instruksi ini ditulis, tetapi saya merasa bahwa itu memberitahu kita bahwa dalam proses pemrosesan permintaan, sistem melakukan tindakan tertentu, dan jika itu "terganggu" oleh permintaan lain, tidak dikirim tepat waktu, ini dapat mengganggu pekerjaannya. Selain itu, fakta bahwa penulis manual mengatakan "beberapa detik" tidak memungkinkan kami untuk mengetahui durasi jeda yang tepat yang harus dipertahankan antara permintaan berturut-turut.
- Item No. 5 dan No. 6. Ini merujuk pada "penggunaan API yang berlebihan," tetapi tidak ada kriteria untuk "penggunaan berlebihan" yang diberikan. Mungkin 10 permintaan per detik? Atau mungkin 1? Selain itu, beberapa proyek web dapat memiliki jumlah lalu lintas yang sangat besar. Jika, tanpa alasan yang memadai dan tanpa pemberitahuan, mereka menutup akses ke API yang mereka butuhkan, administrator mereka kemungkinan besar akan menolak untuk menggunakan API tersebut. Jika Anda menulis instruksi seperti itu, gunakan bahasa yang jelas di dalamnya dan tempatkan diri Anda di tempat pengguna yang harus bekerja dengan sistem Anda, dipandu oleh instruksi Anda.
Masalah nomor 5: dokumentasi
Seperti inilah tampilan dokumentasi API.
Dokumentasi Beds24 APISatu-satunya masalah dengan dokumentasi ini adalah penampilannya. Akan terlihat jauh lebih baik jika diformat dengan baik. Terutama untuk menunjukkan kemungkinan tampilan dokumentasi tersebut, saya, menggunakan
Dillinger , dan menghabiskan kurang dari dua menit untuk itu, membuat versi berikut. Menurut saya, tampilannya jauh lebih baik daripada yang di atas.
Dokumentasi yang ditingkatkanUntuk membuat bahan seperti itu, disarankan untuk menggunakan alat khusus. Jika kita berbicara tentang dokumen sederhana yang mirip dengan yang dijelaskan di atas, maka sesuatu seperti file penurunan harga biasa cukup untuk desainnya. Jika dokumentasi lebih rumit, maka untuk desainnya yang terbaik adalah menggunakan alat seperti
Swagger atau
Apiary .
Omong-omong, jika Anda ingin melihat dokumentasi untuk API Beds24, lihat di
sini .
Masalah 6: Keamanan
Dokumentasi untuk semua titik akhir API mengatakan sebagai berikut:
Untuk menggunakan fungsi-fungsi ini, akses ke API harus diizinkan. Ini dilakukan di menu PENGATURAN โ AKUN โ AKSES AKUN.Namun, pada kenyataannya, siapa pun dapat mengakses API ini, dan, menggunakan beberapa panggilan, dapatkan informasi darinya tanpa memberikan kredensial apa pun. Misalnya, ini juga berlaku untuk pertanyaan tentang ketersediaan tempat tinggal tertentu. Ini dibahas di bagian lain dari dokumentasi.
Sebagian besar metode JSON memerlukan kunci API untuk mengakses akun. Kunci akses API dapat diatur menggunakan menu PENGATURAN โ ACCOUNT โ ACCOUNT ACCESS.Selain penjelasan yang tidak dapat dipahami tentang masalah otentikasi, ternyata pengguna harus membuat kunci untuk mengakses API sendiri (ini dilakukan, dengan cara, dengan mengisi secara manual di bidang yang sesuai, beberapa cara untuk membuat kunci secara otomatis tidak disediakan). Panjang kunci harus antara 16 dan 64 karakter. Jika Anda mengizinkan pengguna untuk membuat kunci sendiri untuk mengakses API, ini dapat menyebabkan munculnya kunci yang sangat tidak aman yang dapat dengan mudah diambil. Dalam situasi yang serupa, masalah yang terkait dengan konten tombol dimungkinkan, karena Anda dapat memasukkan apa pun di bidang kunci. Dalam kasus terburuk, ini dapat menyebabkan serangan pada layanan menggunakan injeksi SQL atau sesuatu seperti itu. Saat merancang API, jangan izinkan pengguna membuat kunci untuk mengakses API itu sendiri. Sebaliknya, buat kunci untuk mereka secara otomatis. Pengguna seharusnya tidak dapat mengubah konten kunci seperti itu, tetapi, jika perlu, ia harus dapat membuat kunci baru, mengakui yang lama sebagai tidak valid.
Dalam hal permintaan yang membutuhkan otentikasi, kami melihat masalah lain. Terdiri dari fakta bahwa token otentikasi harus dikirim sebagai bagian dari badan permintaan. Berikut ini penjelasannya dalam dokumentasi.
Contoh Otentikasi Beds24 APIJika token otentikasi ditransmisikan dalam tubuh permintaan, ini berarti bahwa server harus mem-parsing tubuh permintaan sebelum mencapai kunci. Setelah itu, dia mengekstrak kunci, melakukan otentikasi, dan kemudian memutuskan - apa yang harus dia lakukan dengan permintaan - untuk memenuhinya atau tidak. Jika otentikasi berhasil, maka server tidak akan dikenakan beban tambahan, karena dalam hal ini badan permintaan masih harus diuraikan. Tetapi jika permintaan gagal untuk mengotentikasi, maka waktu prosesor yang berharga akan dihabiskan untuk mem-parsing badan permintaan secara gratis. Akan lebih baik untuk mengirim token otentikasi di header permintaan, menggunakan sesuatu seperti skema otentikasi
Bearer . Dengan pendekatan ini, server hanya perlu mengurai badan permintaan jika otentikasi berhasil. Alasan lain yang kami sarankan untuk menggunakan skema standar seperti Bearer untuk otentikasi adalah kenyataan bahwa sebagian besar pengembang terbiasa dengan skema tersebut.
Masalah nomor 7: kinerja
Ini adalah masalah terakhir dalam daftar saya, tetapi tidak mengurangi arti pentingnya. Faktanya adalah bahwa dibutuhkan sedikit lebih dari satu detik untuk menyelesaikan permintaan ke API yang bersangkutan. Dalam aplikasi modern, penundaan seperti itu mungkin tidak dapat diterima. Faktanya, di sini Anda dapat menyarankan semua orang yang terlibat dalam pengembangan API agar tidak melupakan kinerja.
Ringkasan
Terlepas dari semua masalah yang kami bicarakan di sini, API yang dipermasalahkan memungkinkan kami untuk menyelesaikan masalah yang dihadapi proyek. Tetapi pengembang membutuhkan cukup banyak waktu untuk memahami API dan mengimplementasikan semua yang mereka butuhkan. Selain itu, untuk menyelesaikan masalah sederhana, mereka harus menulis kode yang agak rumit. Jika API ini dirancang sebagaimana mestinya, pekerjaan akan dilakukan lebih cepat, dan solusi turnkey akan lebih sederhana.
Oleh karena itu, saya ingin meminta semua orang yang merancang API untuk berpikir tentang bagaimana pengguna layanan mereka akan bekerja dengannya. Pastikan bahwa dokumentasi untuk API sepenuhnya menggambarkan kapabilitas mereka, sehingga dapat dipahami dan dirancang dengan baik. Kontrol penamaan entitas, pastikan bahwa data yang dipancarkan atau diterima API Anda terstruktur dengan jelas sehingga mudah dan nyaman untuk bekerja dengannya. Selain itu, jangan lupa tentang keamanan dan penanganan kesalahan yang benar. Jika kami mempertimbangkan semua yang kami bicarakan saat merancang API, maka Anda tidak perlu menulis sesuatu seperti "instruksi" aneh yang kami bahas di atas untuk bekerja dengannya.
Seperti yang telah disebutkan, materi ini tidak dimaksudkan untuk mencegah pembaca menggunakan Beds24 atau sistem lain dengan API yang dirancang dengan buruk. Tujuan saya adalah untuk menunjukkan contoh kesalahan dan pendekatan untuk solusi mereka, untuk memberikan rekomendasi, yang mengikuti setiap orang dapat meningkatkan kualitas perkembangan mereka. Saya berharap materi ini akan menarik perhatian programmer yang membacanya dengan kualitas solusi yang mereka kembangkan. Ini berarti akan ada lebih banyak API yang bagus di dunia.
Pembaca yang budiman! Apakah Anda menemukan API yang dirancang dengan buruk?