Bentuk asli dari jawaban ini sangat berbeda, dan dapat ditemukan di sini . Buktinya ada lebih dari satu cara menguliti kucing.
Saya telah memperbarui jawaban sejak menggunakan ruang nama dan menggunakan pengalihan 301 - daripada default 302. Terima kasih kepada pixeltrix dan Bo Jeanes untuk dorongan pada hal-hal itu.
Anda mungkin ingin mengenakan helm yang benar - benar kuat karena ini akan membuat Anda berpikir .
API perutean Rails 3 sangat jahat. Untuk menulis rute untuk API Anda, sesuai kebutuhan Anda di atas, Anda hanya perlu ini:
namespace :api do
namespace :v1 do
resources :users
end
namespace :v2 do
resources :users
end
match 'v:api/*path', :to => redirect("/api/v2/%{path}")
match '*path', :to => redirect("/api/v2/%{path}")
end
Jika pikiran Anda masih utuh setelah titik ini, izinkan saya menjelaskannya.
Pertama, kami memanggil namespace
yang sangat berguna ketika Anda ingin banyak rute dicakup ke jalur dan modul tertentu yang diberi nama serupa. Dalam hal ini, kami ingin semua rute di dalam blok untuk kami namespace
scoping ke controller di dalam Api
modul dan semua permintaan untuk jalur di dalam rute ini akan diawali dengan api
. Permintaan seperti /api/v2/users
, Anda tahu?
Di dalam namespace, kami mendefinisikan dua ruang nama lagi (woah!). Kali ini kita mendefinisikan "v1" namespace, sehingga semua rute untuk kontroler sini akan berada di dalam V1
modul di dalam Api
modul: Api::V1
. Dengan mendefinisikan resources :users
di dalam rute ini, pengontrol akan berlokasi di Api::V1::UsersController
. Ini adalah versi 1, dan Anda sampai di sana dengan membuat permintaan seperti /api/v1/users
.
Versi 2 hanya kecil sedikit berbeda. Alih-alih controller yang menyajikannya berada Api::V1::UsersController
, sekarang di Api::V2::UsersController
. Anda sampai di sana dengan membuat permintaan seperti /api/v2/users
.
Selanjutnya, a match
digunakan. Ini akan cocok dengan semua rute API yang menuju ke hal-hal seperti /api/v3/users
.
Ini adalah bagian yang harus saya cari. The :to =>
pilihan memungkinkan Anda untuk menentukan bahwa permintaan khusus harus diarahkan di tempat lain - saya tahu bahwa banyak - tapi aku tidak tahu bagaimana untuk mendapatkannya untuk mengarahkan ke tempat lain dan lulus dalam sepotong permintaan asli bersama dengan itu .
Untuk melakukan ini, kita memanggil redirect
metode dan meneruskannya string dengan %{path}
parameter interpolasi khusus . Ketika permintaan masuk yang cocok dengan match
tugas akhir ini , itu akan menginterpolasi path
parameter ke lokasi %{path}
di dalam string dan mengarahkan pengguna ke tempat yang mereka tuju.
Akhirnya, kami menggunakan yang lain match
untuk merutekan semua jalur yang tersisa yang diawali /api
dan mengarahkannya ke /api/v2/%{path}
. Ini berarti permintaan seperti /api/users
akan dituju /api/v2/users
.
Saya tidak tahu bagaimana cara /api/asdf/users
mencocokkan, karena bagaimana Anda menentukan apakah itu seharusnya menjadi permintaan /api/<resource>/<identifier>
atau /api/<version>/<resource>
?
Bagaimanapun, ini menyenangkan untuk diteliti dan saya harap ini membantu Anda!
Please note that this redirection is a 301 “Moved Permanently” redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible.
Beberapa hal untuk ditambahkan:
Pencocokan pengalihan Anda tidak akan berfungsi untuk rute tertentu -
*api
param itu serakah dan akan menelan segalanya, misalnya/api/asdf/users/1
akan dialihkan ke/api/v2/1
. Anda akan lebih baik menggunakan param seperti biasa:api
. Memang itu tidak akan cocok dengan kasus seperti/api/asdf/asdf/users/1
tetapi jika Anda memiliki sumber daya bersarang di api Anda itu solusi yang lebih baik.Ryan MENGAPA TIDAK SAYA SUKA
namespace
? :-), mis:Yang memiliki manfaat tambahan dari rute yang diberi nama dan generik. Satu catatan tambahan - konvensi saat menggunakan
:module
adalah menggunakan notasi garis bawah, mis .:api/v1
not 'Api :: V1'. Pada satu titik yang terakhir tidak berfungsi tetapi saya percaya itu diperbaiki di Rails 3.1.Juga, ketika Anda merilis v3 API Anda, rute akan diperbarui seperti ini:
Tentu saja kemungkinan API Anda memiliki rute yang berbeda antar versi dalam hal ini Anda dapat melakukan ini:
sumber
/api/asdf/users?
juga/api/users/1
? Saya tidak bisa mengetahuinya dalam jawaban saya yang diperbarui, jadi saya tahu Anda mungkin tahu caraJika memungkinkan, saya akan menyarankan untuk memikirkan kembali url Anda sehingga versinya tidak ada di url, tetapi dimasukkan ke dalam header accepts. Jawaban stack overflow ini masuk dengan baik:
Praktik terbaik untuk versi API?
dan tautan ini menunjukkan bagaimana melakukannya dengan routing rel:
http://freelancing-gods.com/posts/versioning_your_ap_is
sumber
Saya bukan penggemar versi dengan rute. Kami membuat VersionCake untuk mendukung bentuk versi API yang lebih mudah.
Dengan memasukkan nomor versi API dalam nama file dari masing-masing pandangan kita masing-masing (jbuilder, RABL, dll), kami menjaga agar versi tersebut tidak mengganggu dan memungkinkan degradasi yang mudah untuk mendukung kompatibilitas mundur (mis. Jika v5 tampilan tidak ada, kami render v4 dari view).
sumber
Saya tidak yakin mengapa Anda ingin mengalihkan ke versi tertentu jika suatu versi tidak diminta secara eksplisit. Sepertinya Anda hanya ingin mendefinisikan versi default yang dilayani jika tidak ada versi yang diminta secara eksplisit. Saya juga setuju dengan David Bock bahwa menjaga versi dari struktur URL adalah cara yang lebih bersih untuk mendukung versi.
Steker tak tahu malu: Versionist mendukung kasing ini (dan banyak lagi)
https://github.com/bploetz/versionist
sumber
Jawaban Ryan Bigg bekerja untuk saya.
Jika Anda juga ingin menyimpan parameter kueri melalui pengalihan, Anda dapat melakukannya seperti ini:
sumber
Diterapkan ini hari ini dan menemukan apa yang saya yakini sebagai 'cara yang benar' di RailsCasts - REST API Versioning . Sangat sederhana. Sangat terpelihara. Sangat efektif.
Tambahkan
lib/api_constraints.rb
(bahkan tidak perlu mengubah vnd.example.)Setup
config/routes.rb
seperti ituEdit controller Anda (yaitu
/controllers/api/v1/squads_controller.rb
)Kemudian, Anda dapat mengubah semua tautan di aplikasi dari
/api/v1/squads
menjadi/api/squads
dan Anda dapat MUDAH menerapkan versi api baru tanpa harus mengubah tautansumber