Praktik terbaik untuk versi API? [Tutup]

877

Apakah ada cara yang dikenal atau praktik terbaik untuk versi web layanan REST API?

Saya perhatikan bahwa AWS melakukan versi berdasarkan URL titik akhir . Apakah ini satu-satunya cara atau ada cara lain untuk mencapai tujuan yang sama? Jika ada banyak cara, apa manfaat dari masing-masing cara?

Swaroop CH
sumber

Jawaban:

682

Ini pertanyaan yang bagus dan sulit. Topik desain URI pada saat yang sama merupakan bagian yang paling menonjol dari REST API dan , oleh karena itu, komitmen jangka panjang yang potensial terhadap pengguna API tersebut .

Sejak evolusi suatu aplikasi dan, pada tingkat lebih rendah, API-nya adalah fakta kehidupan dan bahkan mirip dengan evolusi produk yang tampaknya kompleks seperti bahasa pemrograman, desain URI harus memiliki lebih sedikit kendala alami dan harus dilestarikan. lembur . Semakin lama masa pakai aplikasi dan API, semakin besar komitmen untuk pengguna aplikasi dan API.

Di sisi lain, fakta kehidupan lain adalah sulit untuk memperkirakan semua sumber daya dan aspek-aspeknya yang akan dikonsumsi melalui API. Untungnya, tidak perlu mendesain seluruh API yang akan digunakan sampai Kiamat . Cukup untuk mendefinisikan dengan benar semua titik akhir sumber daya dan skema pengalamatan dari setiap instance sumber daya dan sumber daya.

Seiring waktu Anda mungkin perlu menambahkan sumber daya baru dan atribut baru ke setiap sumber daya tertentu, tetapi metode yang diikuti pengguna API untuk mengakses sumber daya tertentu tidak boleh berubah begitu skema pengalamatan sumber daya menjadi publik dan karenanya bersifat final.

Metode ini berlaku untuk semantik kata kerja HTTP (misalnya PUT harus selalu memperbarui / mengganti) dan kode status HTTP yang didukung dalam versi API sebelumnya (mereka harus terus bekerja sehingga klien API yang telah bekerja tanpa campur tangan manusia harus dapat terus bekerja seperti itu).

Selain itu, karena memasukkan versi API ke dalam URI akan mengganggu konsep hypermedia sebagai mesin negara aplikasi (dinyatakan dalam disertasi Roy T. Fieldings PhD) dengan memiliki alamat sumber daya / URI yang akan berubah dari waktu ke waktu, saya akan menyimpulkan bahwa API versi tidak boleh disimpan dalam URI sumber daya untuk waktu yang lama yang berarti bahwa URI sumber daya yang dapat diandalkan pengguna API harus berupa tautan permanen .

Tentu, mungkin untuk menanamkan versi API di URI basis tetapi hanya untuk penggunaan yang wajar dan terbatas seperti men-debug klien API yang bekerja dengan versi API baru. API versi seperti itu harus dibatasi waktu dan hanya tersedia untuk grup terbatas pengguna API (seperti saat beta tertutup). Kalau tidak, Anda mengikat diri sendiri di tempat yang seharusnya tidak Anda lakukan.

Beberapa pemikiran tentang pemeliharaan versi API yang memiliki tanggal kedaluwarsa. Semua platform / bahasa pemrograman yang biasa digunakan untuk mengimplementasikan layanan web (Java, .NET, PHP, Perl, Rails, dll.) Memungkinkan pengikatan titik akhir layanan web dengan mudah ke URI basis. Dengan cara ini, sangat mudah untuk mengumpulkan dan menyimpan koleksi file / kelas / metode yang terpisah di berbagai versi API .

Dari pengguna API POV, itu juga lebih mudah untuk bekerja dengan dan mengikat ke versi API tertentu ketika ini jelas tetapi hanya untuk waktu yang terbatas, yaitu selama pengembangan.

Dari POV pengelola API, lebih mudah untuk mempertahankan berbagai versi API secara paralel dengan menggunakan sistem kontrol sumber yang sebagian besar bekerja pada file sebagai unit terkecil dari versi (kode sumber).

Namun, dengan versi API yang terlihat jelas di URI ada peringatan: orang mungkin juga menolak pendekatan ini karena riwayat API menjadi terlihat / berbeda dalam desain URI dan karena itu rentan terhadap perubahan dari waktu ke waktu yang bertentangan dengan pedoman REST. Saya setuju!

Cara untuk mengatasi keberatan yang masuk akal ini, adalah dengan mengimplementasikan versi API terbaru di bawah URI basis versi API. Dalam hal ini, pengembang klien API dapat memilih untuk:

  • berkembang melawan yang terbaru (berkomitmen untuk mempertahankan aplikasi yang melindunginya dari perubahan API yang mungkin merusak klien API mereka yang dirancang dengan buruk ).

  • ikat ke API versi tertentu (yang menjadi jelas) tetapi hanya untuk waktu yang terbatas

Misalnya, jika API v3.0 adalah versi API terbaru, dua berikut ini harus alias (yaitu berperilaku identik dengan semua permintaan API):

http: // shonzilla / api / pelanggan / 1234 
http: // shonzilla / api /v3.0 / customers / 1234
http: // shonzilla / api / v3 / customers / 1234

Selain itu, klien API yang masih mencoba menunjuk ke API lama harus diberi tahu untuk menggunakan versi API terbaru sebelumnya, jika versi API yang mereka gunakan sudah usang atau tidak didukung lagi . Jadi mengakses salah satu URI usang seperti ini:

http: // shonzilla / api /v2.2 / customers / 1234
http: // shonzilla / api /v2.0 / customers / 1234
http: // shonzilla / api / v2 / customers / 1234
http: // shonzilla / api /v1.1 / customers / 1234
http: // shonzilla / api / v1 / customers / 1234

harus mengembalikan salah satu dari kode status HTTP 30x yang menunjukkan pengalihan yang digunakan bersama dengan Locationheader HTTP yang mengalihkan ke versi sumber daya URI yang sesuai yang tetap seperti ini:

http: // shonzilla / api / customers / 1234

Setidaknya ada dua kode status HTTP pengalihan yang sesuai untuk skenario versi API:

  • 301 Dipindahkan secara permanen yang menunjukkan bahwa sumber daya dengan URI yang diminta dipindahkan secara permanen ke URI lain (yang seharusnya merupakan permalink sumber daya contoh yang tidak mengandung info versi API). Kode status ini dapat digunakan untuk menunjukkan versi API yang usang / tidak didukung, memberi tahu klien API bahwa URI sumber daya berversi telah digantikan oleh permalink sumber daya .

  • 302 Ditemukan menunjukkan bahwa sumber daya yang diminta untuk sementara berada di lokasi lain, sementara URI yang diminta mungkin masih didukung. Kode status ini mungkin berguna ketika URI versi-kurang sementara tidak tersedia dan bahwa permintaan harus diulang menggunakan alamat pengalihan (mis. Menunjuk URI dengan versi APi tertanam) dan kami ingin memberi tahu klien untuk tetap menggunakannya (yaitu permalinks).

  • skenario lain dapat ditemukan di bab Redirection 3xx dari spesifikasi HTTP 1.1

Shonzilla
sumber
142
Menggunakan nomor versi di URL tidak boleh dianggap praktik buruk ketika implementasi yang mendasarinya berubah. "Ketika antarmuka ke layanan berubah dengan cara yang tidak kompatibel, pada kenyataannya layanan yang sama sekali baru telah dibuat ... Dari perspektif klien, layanan tidak lebih dari antarmuka dan beberapa kualitas non-fungsional .. . jika antarmuka ke layanan berubah dengan cara yang tidak kompatibel, itu tidak lagi mewakili turunan dari layanan asli, tetapi lebih merupakan layanan yang sama sekali baru. " ibm.com/developerworks/webservices/library/ws-version
benvolioT
7
Apakah Anda memiliki pemikiran untuk menambahkan header dengan nomor versi sehingga dapat diperiksa oleh klien atau pengembang?
webclimber
11
Lihat juga penggunaan tajuk Terima untuk menunjukkan versi yang diharapkan klien: blog.steveklabnik.com/2011/07/03/...
Weston Ruter
52
Untuk bagian terakhir: Saya akan mengatakan bahwa API yang sudah usang dan tidak didukung lagi akan kembali 410 Gone, karena pengalihan mungkin menunjukkan bahwa lokasi baru itu kompatibel ketika tidak. Jika API hanya usang tetapi masih ada, WarningHeader HTTP pada Respons mungkin menjadi opsi.
Michael Stum
22
Bagaimana Anda menangani klien yang sudah menggunakan URL stabil seperti shonzilla / api / customers / 1234 dan Anda ingin memutakhirkan ke versi baru? bagaimana Anda bisa memaksa mereka menambahkan V2 (yang lama) ke URL?
Dejell
273

URL TIDAK boleh berisi versi. Versi ini tidak ada hubungannya dengan "ide" dari sumber daya yang Anda minta. Anda harus mencoba menganggap URL sebagai jalur menuju konsep yang Anda inginkan - bukan bagaimana Anda ingin item dikembalikan. Versi menentukan representasi objek, bukan konsep objek. Seperti yang dikatakan poster lain, Anda harus menentukan format (termasuk versi) di header permintaan.

Jika Anda melihat permintaan HTTP lengkap untuk URL yang memiliki versi, tampilannya seperti ini:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

Header berisi baris yang berisi representasi yang Anda minta ("Terima: aplikasi / xml"). Di situlah versi harus pergi. Semua orang tampaknya mengabaikan fakta bahwa Anda mungkin menginginkan hal yang sama dalam format yang berbeda dan bahwa klien harus dapat menanyakan apa yang diinginkannya. Dalam contoh di atas, klien meminta representasi XML APAPUN dari sumber daya - bukan representasi sebenarnya dari apa yang diinginkan. Secara teori, server dapat mengembalikan sesuatu yang sama sekali tidak terkait dengan permintaan selama itu XML dan harus diurai untuk menyadari bahwa itu salah.

Cara yang lebih baik adalah:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Lebih jauh, katakanlah klien berpikir XML terlalu bertele-tele dan sekarang mereka menginginkan JSON. Dalam contoh lain Anda harus memiliki URL baru untuk pelanggan yang sama, sehingga Anda akan berakhir dengan:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(atau yang serupa). Padahal, setiap permintaan HTTP berisi format yang Anda cari:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

Dengan menggunakan metode ini, Anda memiliki lebih banyak kebebasan dalam desain dan benar-benar mengikuti ide asli REST. Anda dapat mengubah versi tanpa mengganggu klien, atau secara bertahap mengubah klien karena API diubah. Jika Anda memilih untuk berhenti mendukung representasi, Anda dapat menanggapi permintaan dengan kode status HTTP atau kode khusus. Klien juga dapat memverifikasi respons dalam format yang benar, dan memvalidasi XML.

Ada banyak keuntungan lain dan saya membahas beberapa di sini di blog saya: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Satu contoh terakhir untuk menunjukkan bagaimana menempatkan versi di URL itu buruk. Katakanlah Anda ingin beberapa informasi di dalam objek, dan Anda telah mengversi berbagai objek Anda (pelanggan adalah v3.0, pesanan adalah v2.0, dan objek shipto adalah v4.2). Berikut adalah URL jahat yang harus Anda berikan pada klien:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/
jeremyh
sumber
10
Menangani versi kontrak data independen dan versi kontrak layanan di header Terima tampaknya berantakan sebanyak berantakan di URL. Apakah ada opsi lain? Juga jika saya memiliki beberapa titik akhir (sabun, istirahat), haruskah ini juga ditunjukkan dalam Terima dan biarkan layanan perutean di ujung server menentukan arah ke titik akhir yang benar ATAU dapatkah titik akhir dikodekan dalam URL?
ideafountain
117
Saya tidak bisa setuju dengan ini, setidaknya sampai pada alasan terakhir Anda. Ini sepertinya mengatakan bahwa bagian-bagian berbeda dari URI memiliki versi yang berbeda. Tapi itu bukan poin dari versi API. Intinya adalah memiliki SATU versi untuk sumber daya SELURUH. Jika Anda mengubah versi, ini sumber API yang berbeda. Itu sebabnya tidak masuk akal untuk melihat company.com/api/v3.0/customer/123/v2.0/orders/4321 melainkan company.com/api/v3.0/customer/123/orders/4321 Anda tidak membuat versi bagian apa pun dari sumber daya, Anda mengubah versi sumber daya secara keseluruhan.
fool4jesus
90
Semantik menggunakan nomor versi di header sepertinya lebih baik. Tetapi jauh lebih praktis menggunakan URL: lebih sedikit rawan kesalahan, paling baik di-debug, mudah dilihat oleh pengembang, mudah dimodifikasi pada klien pengujian lainnya.
Daniel Cerecedo
7
Saya pikir BURUK / BAIK atas menyederhanakan pertanyaan. API singkatan dari "Application programming interface" dan antarmuka versi tampaknya merupakan ide yang sangat bagus. API bukan hanya tentang melayani sumber daya. Apa yang perlu dipisahkan adalah bahwa beberapa orang berbicara tentang antarmuka dan orang lain berbicara tentang sumber daya. Jika Anda melihat api Google maps di tab jaringan, Anda akan melihat bahwa mereka memasukkan nomor versi api di url. Misalnya: maps.google.com/maps/api/jsv2 selama otentikasi. Jsv2 adalah nomor api.
Tom Gruner
6
@Gili: Sebenarnya, Anda tidak boleh lagi menggunakan -xkarena sudah ditinggalkan oleh RFC6648 .
Jonathan W
98

Kami merasa praktis dan bermanfaat untuk meletakkan versi di URL. Sangat mudah untuk mengetahui apa yang Anda gunakan sekilas. Kami melakukan alias / foo ke / foo / (versi terbaru) untuk kemudahan penggunaan, URL yang lebih pendek / lebih bersih, dll, seperti yang disarankan oleh jawaban yang diterima.

Menjaga kompatibilitas ke belakang selamanya seringkali mahal dan / atau sangat sulit. Kami lebih suka memberikan pemberitahuan penghentian, pengalihan seperti yang disarankan di sini, dokumen, dan mekanisme lainnya.

Yoav Shapira
sumber
5
Jawaban yang diterima mungkin yang benar dan paling murni. Namun, untuk pengembang dan pengguna API sehari-hari ini tentunya yang paling mudah digunakan dan diatur. Pendekatan yang paling pragmatis. Seperti yang ditunjukkan oleh Google dan Amazon lain juga menggunakan pendekatan ini.
Muhammad Rehan Saeed
46

Saya setuju bahwa versi representasi sumber daya lebih baik mengikuti pendekatan REST ... tapi, satu masalah besar dengan tipe MIME khusus (atau tipe MIME yang menambahkan parameter versi) adalah dukungan yang buruk untuk menulis ke header Terima dan Konten-Jenis dalam HTML dan JavaScript.

Misalnya, IMO ke POST tidak mungkin dengan tajuk berikut dalam bentuk HTML5, untuk membuat sumber daya:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

Ini karena enctypeatribut HTML5 adalah enumerasi, karena itu apa pun selain yang biasa application/x-www-formurlencoded, multipart/form-datadan text/plaintidak valid.

... saya juga tidak yakin itu didukung di semua browser dalam HTML4 (yang memiliki atribut encytpe lebih longgar, tetapi akan menjadi masalah implementasi browser, apakah tipe MIME diteruskan)

Karena ini saya sekarang merasa cara yang paling tepat untuk versi adalah melalui URI, tetapi saya menerima bahwa itu bukan cara yang 'benar'.

Kevsy
sumber
14
Dengan asumsi rute di mana versi didefinisikan dalam header, orang dapat mengatakan bahwa formulir HTML yang menggunakan pengiriman formulir asli akan selalu menggunakan versi terbaru dari API karena mereka tidak akan melewati versi spesifik yang ingin mereka patuhi. Namun, permintaan XHR memang memungkinkan Anda untuk mengubah penerimaan dan membaca header tipe konten. Jadi bentuk dasar adalah satu-satunya masalah.
Kyle Hayes
Saya tidak yakin saya setuju bahwa URI adalah yang paling tepat, tetapi fakta bahwa Content-Type tidak bekerja dengan form memang sangat penting.
wprl
2
@Kyle, saya melihat blog di suatu tempat mengatakan bahwa jika Anda tidak menentukan versi di header permintaan, yang terbaik adalah kembali dengan versi api pertama bukan yang terbaru untuk kompatiable terbaik.
andy
Itu benar-benar masuk akal bagi saya sekarang setelah saya pikirkan.
Kyle Hayes
@KyleHayes jangan lupa tag iframe, video / embed dan tag jenis "src / href" lainnya.
plve
21

Masukkan versimu di URI. Satu versi API tidak akan selalu mendukung jenis dari yang lain, sehingga argumen bahwa sumber daya hanya dimigrasikan dari satu versi ke versi lain adalah salah. Ini tidak sama dengan beralih format dari XML ke JSON. Jenisnya mungkin tidak ada, atau mungkin berubah secara semantik.

Versi adalah bagian dari alamat sumber daya. Anda merutekan dari satu API ke API lainnya. Itu tidak tenang untuk menyembunyikan pengalamatan di header.

Sean O'Dell
sumber
13

Ada beberapa tempat yang dapat Anda lakukan untuk membuat versi dalam REST API:

  1. Seperti dicatat, di URI. Ini dapat ditelusuri dan bahkan secara estetika menyenangkan jika pengalihan dan sejenisnya digunakan dengan baik.

  2. Di header Accepts:, maka versinya ada dalam filetype. Seperti 'mp3' vs 'mp4'. Ini juga akan berfungsi, meskipun IMO berfungsi sedikit lebih baik daripada ...

  3. Di sumber daya itu sendiri. Banyak format file memiliki nomor versi yang disematkan di dalamnya, biasanya di header; ini memungkinkan perangkat lunak yang lebih baru untuk 'hanya berfungsi' dengan memahami semua versi filetype yang ada sementara perangkat lunak yang lebih lama dapat menyepak bola jika versi (yang lebih baru) tidak didukung didukung. Dalam konteks API REST, itu artinya URI Anda tidak perlu berubah, cukup respons Anda terhadap versi data tertentu yang Anda serahkan.

Saya bisa melihat alasan untuk menggunakan ketiga pendekatan:

  1. jika Anda suka melakukan 'pembersihan bersih' API baru, atau untuk perubahan versi utama di mana Anda menginginkan pendekatan seperti itu.
  2. jika Anda ingin klien tahu sebelum PUT / POST apakah itu akan berfungsi atau tidak.
  3. jika tidak apa-apa jika klien harus melakukan PUT / POST untuk mencari tahu apakah itu akan berhasil.
pjz
sumber
8

Versi API REST Anda analog dengan versi API lainnya. Perubahan kecil dapat dilakukan, perubahan besar mungkin memerlukan API baru. Cara termudah bagi Anda adalah mulai dari awal setiap saat, yaitu saat menempatkan versi di URL paling masuk akal. Jika Anda ingin membuat hidup lebih mudah bagi klien Anda mencoba untuk mempertahankan kompatibilitas mundur, yang dapat Anda lakukan dengan penghentian (pengalihan permanen), sumber daya dalam beberapa versi dll. Ini lebih fiddly dan membutuhkan lebih banyak usaha. Tapi itu juga yang didorong oleh REST di "Cool URIs tidak berubah".

Pada akhirnya itu sama seperti desain API lainnya. Timbang upaya terhadap kenyamanan klien. Pertimbangkan untuk mengadopsi versi semantik untuk API Anda, yang menjelaskan kepada klien Anda seberapa kompatibel versi baru Anda.

Alexander Torstling
sumber