Управление версиями API для маршрутов Rails
Я пытаюсь версию моего API, как полоса имеет. Ниже приведена последняя версия API - 2.
/api/users
возвращает 301 в /api/v2/users
/api/v1/users
возвращает индекс 200 пользователей в версии 1
/api/v3/users
возвращает 301 в /api/v2/users
/api/asdf/users
возвращает 301 в /api/v2/users
так что в основном все, что не указывает ссылки на последнюю версию, если только указанная версия не существует, перенаправляется на оно.
это то, что у меня есть до сих пор:
scope 'api', :format => :json do
scope 'v:api_version', :api_version => /[12]/ do
resources :users
end
match '/*path', :to => redirect { |params| "/api/v2/#{params[:path]}" }
end
6 ответов:
оригинальная форма этого ответа дико отличается, и ее можно найти здесь. Просто доказательство того, что есть более чем один способ освежевать кошку.
я обновил ответ, так как использовать пространства имен и использовать 301 редирект, а не по умолчанию 302. Спасибо pixeltrix и Bo Jeanes за подсказку по этим вещам.
вы можете носить действительно крепкий шлем, потому что это будет удар ваш ум.
Rails 3 routing API-это супер злой. Чтобы написать маршруты для вашего API, в соответствии с вашими требованиями выше, вам нужно только это:
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
если ваш ум все еще цел после этого момента, позвольте мне объяснить.
во-первых, мы называем
namespace
что очень удобно, когда вы хотите, чтобы куча маршрутов была привязана к определенному пути и модулю с аналогичным именем. В этом случае, мы хотим, чтобы все маршруты внутри блока для нашихnamespace
Для быть ограничен для контроллеров в пределахApi
модуль и все запросы к путям внутри этого маршрута будут иметь префиксapi
. Такие запросы, как/api/v2/users
, Я знаю?внутри пространства имен мы определяем еще два пространства имен (woah!). На этот раз мы определяем пространство имен "v1", поэтому все маршруты для контроллеров здесь будут находиться внутри
V1
модульApi
модуль:Api::V1
. Определениемresources :users
внутри этого маршрута, контроллер будет находиться вApi::V1::UsersController
. Это версия 1, и вы получаете там, делая запросы, как/api/v1/users
.Версия 2-это только крошечные несколько иначе. Вместо контроллера, обслуживающего его, он находится в
Api::V1::UsersController
, сейчас наApi::V2::UsersController
. Вы получаете там, делая запросы, как/api/v2/users
.далее, a это. Это будет соответствовать всем маршрутам API, которые идут к таким вещам, как
/api/v3/users
.это та часть,которую я должен был посмотреть. Элемент
:to =>
опция позволяет указать, что конкретный запрос должен быть перенаправлено куда-то еще-я знал это много-но я не знал, как заставить его перенаправить куда-то еще и передать часть исходного запроса вместе с ним.чтобы сделать это, мы называем
redirect
метод и передать ему строку с интерполированными . Когда приходит запрос, который соответствует этому финалуmatch
, он будет интерполироватьpath
параметр в расположение%{path}
внутри строки и перенаправить пользователя туда, куда им нужно идти.наконец, мы используем другой
match
для маршрутизации всех оставшихся путей с префиксом/api
и перенаправить их в/api/v2/%{path}
. Это означает запросы типа/api/users
пойдет/api/v2/users
.я не мог понять, как получить
/api/asdf/users
чтобы соответствовать, потому что, как вы определяете, если это должен быть запрос/api/<resource>/<identifier>
или/api/<version>/<resource>
?в любом случае, это было интересно и я надеюсь, что это поможет вам!
несколько вещей, чтобы добавить:
ваш редирект матч не будет работать для определенных маршрутов-the
*api
парам жаден и проглотит все, например/api/asdf/users/1
перенаправит к/api/v2/1
. Вам было бы лучше использовать обычный парам, как:api
. По общему признанию, это не будет соответствовать случаи, как/api/asdf/asdf/users/1
но если у вас есть вложенные ресурсы в вашем api, это лучшее решение.Райан почему тебе не нравится
namespace
? :-), электронной.г:current_api_routes = lambda do resources :users end namespace :api do scope :module => :v2, ¤t_api_routes namespace :v2, ¤t_api_routes namespace :v1, ¤t_api_routes match ":api/*path", :to => redirect("/api/v2/%{path}") end
это преимущество версионных и универсальных именованных маршрутов. Еще одно примечание-конвенция при использовании
:module
использовать подчеркивание, например:api/v1
не 'Api:: V1'. В какой-то момент последний не работал, но я считаю, что это было исправлено в Rails 3.1.кроме того, при выпуске v3 вашего API маршруты будут обновлены следующим образом:
current_api_routes = lambda do resources :users end namespace :api do scope :module => :v3, ¤t_api_routes namespace :v3, ¤t_api_routes namespace :v2, ¤t_api_routes namespace :v1, ¤t_api_routes match ":api/*path", :to => redirect("/api/v3/%{path}") end
конечно, вполне вероятно, что ваш API имеет разные маршруты между версиями, и в этом случае вы можете сделать это:
current_api_routes = lambda do # Define latest API end namespace :api do scope :module => :v3, ¤t_api_routes namespace :v3, ¤t_api_routes namespace :v2 do # Define API v2 routes end namespace :v1 do # Define API v1 routes end match ":api/*path", :to => redirect("/api/v3/%{path}") end
Если это вообще возможно, я бы предложил переосмыслить ваши URL-адреса, чтобы версия не была в url-адресе, а помещалась в заголовок accepts. Этот ответ переполнения стека входит в него хорошо:
рекомендации по управлению версиями API?
и эта ссылка показывает, как именно это сделать с маршрутизацией rails:
Я не большой поклонник версий по маршрутам. Мы построили VersionCake для поддержки более простой формы управления версиями API.
включив номер версии API в имя файла каждого из наших соответствующих представлений (jbuilder, RABL и т. д.), Мы сохраняем версию ненавязчивой и допускаем легкую деградацию для поддержки обратной совместимости (например, если v5 представления не существует, мы визуализируем v4 представления).
Я не уверен, почему вы хотите редирект к определенной версии, если версия не запрашивается явно. Похоже, вы просто хотите определить версию по умолчанию, которая обслуживается, если версия не запрашивается явно. Я также согласен с Дэвидом боком, что сохранение версий из структуры URL-это более чистый способ поддержки управления версиями.
бесстыдный плагин: Versionist поддерживает эти варианты использования (и более.)