Apa yang merupakan pola yang direkomendasikan untuk perencanaan titik akhir REST untuk perubahan pandangan jauh ke depan

25

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 /apibersama dengan /authdan 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, DELETEbukan 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 sendtitik 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."

Brett Ryan
sumber

Jawaban:

13

Jadi ada pertanyaan kedua saya "Apa cara terbaik untuk merancang kode layanan REST untuk mendukung versi sebelumnya."

API ortogonal yang dirancang dengan sangat hati-hati dan mungkin tidak akan pernah perlu diubah dengan cara yang tidak kompatibel ke belakang, jadi sebenarnya cara terbaik adalah tidak memiliki versi masa depan.

Tentu saja, Anda mungkin tidak akan benar-benar mendapatkan yang pertama kali mencoba; Begitu:

  • Versi API Anda, sama seperti yang Anda rencanakan (dan itu API yang diversi, bukan metode individual di dalamnya), dan membuat banyak kebisingan tentang hal itu. Pastikan mitra Anda tahu bahwa API dapat berubah, dan bahwa aplikasi mereka harus memeriksa untuk melihat apakah mereka menggunakan versi terbaru; dan menyarankan pengguna untuk memutakhirkan ketika yang lebih baru tersedia. Mendukung dua versi lama itu sulit, mendukung lima tidak dapat dipertahankan.
  • Tahan keinginan untuk memperbarui versi API dengan setiap "rilis". Fitur-fitur baru biasanya dapat dimasukkan ke versi saat ini tanpa merusak klien yang sudah ada; mereka fitur baru. Hal terakhir yang Anda inginkan adalah klien mengabaikan nomor versi, karena sebagian besar kompatibel ke belakang. Hanya perbarui versi API ketika Anda benar-benar tidak dapat bergerak maju tanpa merusak API yang ada.
  • Ketika tiba saatnya untuk membuat versi baru, klien pertama harus menjadi implementasi yang kompatibel dengan versi sebelumnya. "API pemeliharaan" itu sendiri harus diterapkan pada API saat ini. Dengan cara ini Anda tidak berada di hook untuk mempertahankan beberapa implementasi penuh; hanya versi saat ini, dan beberapa "kerang" untuk versi lama. Menjalankan tes regresi untuk API yang saat ini sudah tidak berlaku lagi terhadap klien comaptible mundur adalah cara yang baik untuk menguji API baru dan lapisan kompatibilitas.
SingleNegationElimination
sumber
3

Opsi desain URI pertama mengekspresikan ide yang lebih baik bahwa Anda mengversi seluruh API. Yang kedua dapat diartikan sebagai versi pesan sendiri. Jadi ini IMO yang lebih baik:

rest.product.com/api/v1/messages/send

Untuk pustaka klien saya pikir menggunakan dua implementasi penuh dalam paket Java terpisah lebih bersih, lebih mudah digunakan dan lebih mudah dirawat.

Yang sedang berkata, ada metode yang lebih baik untuk mengembangkan API daripada versi. Saya setuju dengan Anda bahwa Anda harus siap untuk itu, tetapi saya menganggap versi sebagai metode pilihan terakhir, untuk digunakan dengan hati-hati dan hemat. Ini merupakan upaya yang relatif besar bagi klien untuk memutakhirkan. Beberapa waktu yang lalu saya menaruh beberapa pemikiran ini dalam posting blog:

http://theamiableapi.com/2011/10/18/api-design-best-practice-plan-for-evolution/

Untuk versi REST API khusus, Anda akan menemukan posting ini oleh Mark Nottingham bermanfaat:

http://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown

Ferenc Mihaly
sumber
3

Pendekatan lain untuk menangani versi API adalah dengan menggunakan Version in HTTP Headers. Seperti

POST /messages/list/{user} HTTP/1.1
Host: http://rest.service.com
Content-Type: application/json
API-Version: 1.0      <----- like here
Cache-Control: no-cache

Anda dapat mengurai header dan menanganinya dengan tepat di backend.

Dengan pendekatan ini klien tidak perlu mengubah URL, cukup header. Dan ini juga membuat titik akhir REST lebih bersih, selalu.

Jika salah satu klien tidak mengirim tajuk versi, Anda mengirim 400 - Permintaan salah atau Anda dapat menanganinya dengan versi API yang kompatibel dengan backward .

sincekamal
sumber