Wersjonowanie API dla tras Rails

Próbuję wersję mojego API jak Stripe ma. Poniżej podano najnowszą wersję API jest 2.

/api/users zwraca 301 do /api/v2/users

/api/v1/users zwraca indeks 200 użytkowników w wersji 1

/api/v3/users zwraca 301 do /api/v2/users

/api/asdf/users zwraca 301 do /api/v2/users

Tak, że w zasadzie wszystko, co nie określa wersji, łączy się z najnowszą, chyba że określona wersja istnieje, a następnie przekierowuje do niej.

Oto co mam do tej pory:

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
Author: Charles, 2012-03-09

6 answers

Oryginalna forma tej odpowiedzi jest szalenie inna i można ją znaleźć tutaj . Tylko dowód, że jest więcej niż jeden sposób na oskórowanie kota.

Zaktualizowałem odpowiedź, aby używać przestrzeni nazw i używać przekierowań 301 -- zamiast domyślnego 302. Dzięki pixeltrix i Bo Jeanes za podpowiedź na tych rzeczach.


Możesz chcieć założyć naprawdę mocny kask, bo to cię rozwali.

Szyny 3 routing API jest super zły. Aby napisać trasy dla swojego API, zgodnie z powyższymi wymaganiami, potrzebujesz tylko tego: [34]}

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

Jeśli twój umysł jest nadal nienaruszony po tym punkcie, pozwól mi wyjaśnić.

Po pierwsze, wywołujemy namespace, co jest bardzo przydatne, gdy chcesz, aby kilka tras przypisanych do określonej ścieżki i modułu o podobnej nazwie. W tym przypadku chcemy, aby wszystkie trasy wewnątrz bloku dla naszego namespace były scopowane do kontrolerów w module Api i wszystkie żądania do ścieżek wewnątrz tej trasy będzie poprzedzony znakiem api. Prośby takie jak /api/v2/users, wiesz?

Wewnątrz przestrzeni nazw definiujemy dwie kolejne przestrzenie nazw (woah!). Tym razem definiujemy przestrzeń nazw "v1", więc wszystkie trasy dla kontrolerów będą wewnątrz modułu V1 wewnątrz modułu Api: Api::V1. Definiując resources :users wewnątrz tej trasy, kontroler będzie znajdował się pod adresem Api::V1::UsersController. To jest wersja 1, i dostajesz się tam, składając prośby w stylu /api/v1/users.

Wersja 2 jest tylko mały trochę inny. Zamiast kontrolera obsługującego to jest w Api::V1::UsersController, jest teraz w Api::V2::UsersController. Dostajesz się tam, składając prośby w stylu /api/v2/users.

Następny, match jest używany. Będzie to pasować do wszystkich tras API, które prowadzą do rzeczy takich jak /api/v3/users.

To jest ta część, którą musiałem sprawdzić. Opcja :to => pozwala określić, że konkretne żądanie powinno być przekierowane gdzieś indziej-wiedziałem tyle - ale nie wiedziałem, jak go zmusić do przekierowania gdzieś indziej i przekazać w fragment pierwotnego wniosku wraz z nim.

W tym celu wywołujemy metodę redirect i przekazujemy jej ciąg znaków ze specjalnym interpolowanym parametrem %{path}. Gdy pojawi się żądanie, które pasuje do tego ostatniego match, interpoluje parametr path do lokalizacji %{path} wewnątrz łańcucha i przekierowuje użytkownika tam, gdzie musi się udać.

Na koniec, używamy innego match, aby wytyczyć wszystkie pozostałe ścieżki poprzedzone /api i przekierować je na /api/v2/%{path}. Oznacza to żądania jak /api/users pójdzie do /api/v2/users.

Nie mogłem wymyślić, jak uzyskać /api/asdf/users aby dopasować, bo jak ustalić, czy to ma być prośba do /api/<resource>/<identifier> czy /api/<version>/<resource>?

W każdym razie, to było zabawne do badania i mam nadzieję, że to pomoże!

 274
Author: Ryan Bigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:10

Kilka rzeczy do dodania:

Twoje dopasowanie przekierowań nie zadziała na określone trasy - param *api jest chciwy i pochłonie wszystko, np. /api/asdf/users/1 przekieruje na /api/v2/1. Lepiej używaj zwykłego param jak :api. Co prawda nie będzie pasować do przypadków takich jak /api/asdf/asdf/users/1, ale jeśli masz zagnieżdżone zasoby w swoim api, jest to lepsze rozwiązanie.

Ryan WHY U NO LIKE namespace? :- ), np.:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v2, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v2/%{path}")
end

Który ma dodatkową zaletę wersji i nazw rodzajowych trasy. Jedna dodatkowa uwaga-przy użyciu :module należy używać notacji podkreślenia, np.: api/v1, a nie 'Api:: V1'. W pewnym momencie Ten ostatni nie działał, ale wierzę, że został naprawiony w Rails 3.1.

Również, gdy wydasz v3 swojego API, trasy będą aktualizowane w następujący sposób:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v3/%{path}")
end

Oczywiście jest prawdopodobne, że Twoje API ma różne trasy między wersjami, w takim przypadku możesz to zrobić:

current_api_routes = lambda do
  # Define latest API
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_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
 37
Author: pixeltrix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-09 06:47:01

Jeśli to w ogóle możliwe, sugerowałbym ponowne przemyślenie adresów URL, aby wersja nie była w adresie url, ale została umieszczona w nagłówku accepts. Ta odpowiedź na przepełnienie stosu idzie do niego dobrze:

Najlepsze praktyki dotyczące wersjonowania API?

A ten link pokazuje dokładnie jak to zrobić z trasowaniem rails:

Http://freelancing-gods.com/posts/versioning_your_ap_is

 13
Author: David Bock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:44

Nie jestem wielkim fanem wersjonowania po trasach. Zbudowaliśmy VersionCake , aby wspierać łatwiejszą formę wersjonowania API.

Dodając numer wersji API w nazwie pliku każdego z naszych widoków (JBuilder, RABL, itp.), zachowujemy ich wersje dyskretne i umożliwiamy łatwą degradację w celu wsparcia wstecznej kompatybilności(np. jeśli v5 widoku nie istnieje, renderujemy V4 widoku).

 9
Author: aantix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-21 23:58:40

Nie jestem pewien, dlaczego chcesz przekierować do określonej wersji, jeśli wersja nie jest wyraźnie wymagane. Wygląda na to, że po prostu chcesz zdefiniować domyślną wersję, która będzie serwowana, jeśli żadna wersja nie jest wyraźnie wymagana. Zgadzam się również z Davidem Bockiem, że utrzymywanie wersji poza strukturą URL jest czystszym sposobem wspierania wersjonowania.

Shameless plug: Versionist wspiera te przypadki użycia (i nie tylko).

Https://github.com/bploetz/versionist

 8
Author: Brian Ploetz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-12 01:28:52

Odpowiedź Ryana Bigga zadziałała.

Jeśli chcesz również zachować parametry zapytania poprzez przekierowanie, możesz to zrobić w następujący sposób:

match "*path", to: redirect{ |params, request| "/api/v2/#{params[:path]}?#{request.query_string}" }
 0
Author: Amed Rodríguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-20 12:21:25