Mencoba merancang API untuk aplikasi eksternal dengan pandangan ke depan untuk perubahan tidak mudah, tetapi sedikit pemikiran di muka dapat membuat hidup lebih mudah di kemudian hari. Saya mencoba membuat skema yang akan mendukung perubahan di masa depan sambil tetap kompatibel dengan meninggalkan penangan versi sebelumnya di tempat.
Perhatian utama pada artikel ini adalah pola apa yang harus diikuti untuk semua titik akhir yang ditentukan untuk produk / perusahaan tertentu.
basis Skema
Diberi templat URL dasar dari https://rest.product.com/
Saya telah menemukan bahwa semua layanan berada di bawah /api
bersama dengan /auth
dan titik akhir berbasis non-istirahat seperti /doc
. Oleh karena itu saya dapat membangun endpoint dasar sebagai berikut:
https://rest.product.com/api/...
https://rest.product.com/auth/login
https://rest.product.com/auth/logout
https://rest.product.com/doc/...
layanan endpoint
Sekarang untuk titik akhir sendiri. Kekhawatiran tentang POST
, GET
, DELETE
bukan tujuan utama dari artikel ini dan merupakan perhatian pada tindakan-tindakan mereka sendiri.
Titik akhir dapat dipecah menjadi ruang nama dan tindakan. Setiap tindakan juga harus hadir dengan cara untuk mendukung perubahan mendasar dalam tipe pengembalian atau parameter yang diperlukan.
Mengambil layanan obrolan hipotetis tempat pengguna terdaftar dapat mengirim pesan, kami mungkin memiliki titik akhir berikut:
https://rest.product.com/api/messages/list/{user}
https://rest.product.com/api/messages/send
Sekarang untuk menambahkan dukungan versi untuk perubahan API di masa depan yang mungkin melanggar. Kami dapat menambahkan tanda tangan versi setelah /api/
atau setelah /messages/
. Diberikan send
titik akhir kita kemudian dapat memiliki yang berikut untuk v1.
https://rest.product.com/api/v1/messages/send
https://rest.product.com/api/messages/v1/send
Jadi pertanyaan pertama saya adalah, tempat apa yang disarankan untuk pengenal versi?
Mengelola Kode Pengendali
Jadi sekarang kita telah menetapkan kita perlu mendukung versi sebelumnya kita perlu sehingga entah bagaimana menangani kode untuk masing-masing versi baru yang mungkin usang dari waktu ke waktu. Dengan asumsi kita menulis endpoint di Jawa kita bisa mengelola ini melalui paket.
package com.product.messages.v1;
public interface MessageController {
void send();
Message[] list();
}
Ini memiliki keuntungan bahwa semua kode telah dipisahkan melalui ruang nama di mana setiap perubahan berarti bahwa salinan baru dari titik akhir layanan. Kerugiannya adalah bahwa semua kode perlu disalin dan perbaikan bug yang ingin diterapkan ke versi baru dan sebelumnya perlu diterapkan / diuji untuk setiap salinan.
Pendekatan lain adalah membuat penangan untuk setiap titik akhir.
package com.product.messages;
public class MessageServiceImpl {
public void send(String version) {
getMessageSender(version).send();
}
// Assume we have a List of senders in order of newest to oldest.
private MessageSender getMessageSender(String version) {
for (MessageSender s : senders) {
if (s.supportsVersion(version)) {
return s;
}
}
}
}
Ini sekarang mengisolasi versi ke setiap titik akhir itu sendiri dan membuat perbaikan bug port kembali kompatibel dengan dalam banyak kasus hanya perlu diterapkan sekali, tetapi itu berarti bahwa kita perlu melakukan sedikit pekerjaan yang lebih adil untuk setiap titik akhir individu untuk mendukung ini.
Jadi ada pertanyaan kedua saya "Apa cara terbaik untuk merancang kode layanan REST untuk mendukung versi sebelumnya."