Raylar için API Versiyonu


141

Stripe gibi benim API sürüm için çalışıyorum. Aşağıda en son API sürümü 2 verilmiştir.

/api/users 301 döndürür /api/v2/users

/api/v1/users sürüm 1'de 200 kullanıcı dizini döndürür

/api/v3/users 301 döndürür /api/v2/users

/api/asdf/users 301 döndürür /api/v2/users

Böylece, temel olarak sürüm belirtilmemiş herhangi bir şey, belirtilen sürüm mevcut olmadığı sürece en son bağlantıya yönlendirir.

Şimdiye kadar sahip olduğum şey bu:

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

Yanıtlar:


280

Bu cevabın orijinal formu çılgınca farklıdır ve burada bulunabilir . Sadece bir kedinin derisini atmanın birden fazla yolu olduğunu kanıtlayın.

Ad alanlarını kullanmak ve varsayılan 302 yerine 301 yönlendirmelerini kullanmak için cevabı güncelledim. Bu şeyleri sormak için pixeltrix ve Bo Jeanes'e teşekkürler.


Gerçekten güçlü bir kask takmak isteyebilirsiniz çünkü bu aklınızı başınızdan alacak .

Rails 3 yönlendirme API'sı çok kötü. API'niz için rotaları yukarıdaki gereksinimlerinize göre yazmak için sadece buna ihtiyacınız vardır:

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

Bu noktadan sonra zihniniz hala sağlamsa, açıklayayım.

İlk olarak, namespacebelirli bir yola ve benzer şekilde adlandırılmış bir modüle sahip bir grup rota istediğinizde süper kullanışlı olanı çağırıyoruz . Bu durumda, blok içindeki tüm rotaların modül namespaceiçindeki kontrolörlere dahil edilmesini istiyoruz Apive bu rota içindeki yollara yapılan tüm taleplerin önüne ön ek eklenecektir api. Gibi istekler /api/v2/users, biliyor musun?

Ad alanının içinde, iki ad alanı daha tanımlıyoruz (woah!). Burada denetleyicileri için tüm yolları içinde olacaktır böylece bu sefer, "v1" ad tanımlarken V1içeride modül Apimodül: Api::V1. resources :usersBu güzergâhın içinde tanımlayarak , kontrolör bulunacaktır Api::V1::UsersController. Bu sürüm 1, ve gibi istekleri yaparak oraya /api/v1/users.

Sürüm 2 yalnızca bir minik biraz farklı. Ona hizmet eden denetleyici yerine, Api::V1::UsersControllerşu anda Api::V2::UsersController. Gibi isteklerde bulunarak oraya gelirsiniz /api/v2/users.

Ardından, a matchkullanılır. Bu, benzer şeylere giden tüm API rotalarıyla eşleşir /api/v3/users.

Aramam gereken kısım bu. Bu :to =>seçenek, belirli bir isteğin başka bir yere yönlendirileceğini belirtmenize izin verir - çok şey biliyordum - ancak başka bir yere yönlendirmek ve orijinal isteğin bir parçasını onunla birlikte geçirmek için nasıl bilmediğimi bilmiyordum. .

Bunu yapmak için, redirectyöntemi çağırır ve özel enterpolasyonlu bir %{path}parametreye sahip bir dize geçiririz . Bu finalle eşleşen bir istek geldiğinde match, pathparametreyi %{path}dizenin içindeki konuma enterpolasyonlar ve kullanıcıyı gitmesi gereken yere yönlendirir.

Son olarak, matchön ekli kalan tüm yolları /apiyönlendirmek ve yönlendirmek için başka bir yol kullanırız /api/v2/%{path}. Bu, gibi isteklerin /api/usersgideceği anlamına gelir /api/v2/users.

Ben nasıl çözemedim /api/asdf/usersbuna bir istek olması gerekiyordu olmadığını nasıl belirliyorsunuz, çünkü maç için /api/<resource>/<identifier>ya /api/<version>/<resource>?

Her neyse, bu araştırmak eğlenceliydi ve umarım size yardımcı olur!


24
Sevgili Ryan Bigg. Sen harikasın.
erkek öğretmen

18
Kişi sadece bir Ruby Hero'nun itibarını ölçmez.
Waseem

1
Ryan ... Bunun doğru olduğunu düşünmüyorum. Bu, / api ve / api / v2'nin tek bir standart URL yerine aynı içeriği sunmasını sağlar. / api, / api / v2'ye yönlendirmelidir (orijinal yazarın belirttiği gibi). Doğru rotaların gist.github.com/2044335 gibi görünmesini beklerdim (kabul ettim, ama bunu test etmedim). Yalnızca / api / v [12] 200 döndürmeli, / api ve / api / <kötü sürüm> 301s değerini / api / v2'ye döndürmelidir
Bo Jeanes

2
Güzergah dosyasında (301) varsayılan yönlendirme yapıldığını ve iyi bir nedenden ötürü belirtmek gerekir. Rehberlerden: 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.
erkek eğitmen

3
Yol doğru değilse sonsuz yönlendirmeler oluşturmuyor mu? Örneğin, / api / v3 / path_that_dont_match_the_routes istemek sonsuz bir yönlendirme yaratır, değil mi?
Robin

38

Eklenecek birkaç şey:

Yönlendirme *apimaçınız belirli rotalar için işe yaramayacak - param açgözlü ve her şeyi yutacak, örneğin /api/asdf/users/1yönlendirilecek /api/v2/1. Normal bir param kullanmak daha iyi olur :api. Kuşkusuz bu gibi durumlarla eşleşmeyecektir, /api/asdf/asdf/users/1ancak API'nizde iç içe kaynaklar varsa daha iyi bir çözümdür.

Ryan NEDEN GİBİ YOKSUN namespace? :-), Örneğin:

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

Hangi sürüm ve jenerik adlandırılmış yolları ek bir yararı vardır. Bir ek not - kullanırken kural :modulealt çizgi gösterimi kullanmaktır, örneğin: api/v1'Api :: V1' değil. Bir noktada ikincisi işe yaramadı, ancak Rails 3.1'de düzeltildiğine inanıyorum.

Ayrıca, API'nizin v3 sürümünü bıraktığınızda yollar şu şekilde güncellenir:

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

Elbette, API'nızın sürümler arasında farklı yollar olması muhtemeldir, bu durumda bunu yapabilirsiniz:

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

Nihai dava ile nasıl başa çıkardınız? yani /api/asdf/users?aynı zamanda /api/users/1? Güncellenmiş cevabımda bunu anlayamadım, bu yüzden bir yol bileceğinizi düşündüm
Ryan Bigg

Bunu yapmanın kolay bir yolu yok - tümünü yakalamadan önce tüm yönlendirmeleri tanımlamanız gerekir, ancak her bir ana kaynak için her birini yapmanız gerekir, örneğin / api / users / * path => / api / v2 / users /% {path}
12'de pixeltrix

13

Mümkünse, sürümün url'de olmaması, ancak kabul üstbilgisine konması için URL'lerinizi yeniden düşünmenizi öneririm. Bu yığın taşması yanıtı iyi gider:

API sürümleri için en iyi uygulamalar?

ve bu bağlantı rayların yönlendirilmesiyle tam olarak nasıl yapılacağını gösterir:

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


Bu da bunu yapmanın mükemmel bir yoludur ve muhtemelen "/ api / asdf / users" isteğine de hitap eder.
Ryan Bigg

9

Ben yollarla versiyonlama büyük bir hayranı değilim. Biz inşa VersionCake API sürümleri daha kolay bir şeklini destekleyecek.

API sürüm numarasını her bir görünümümüzün (jbuilder, RABL, vb.) Dosya adına ekleyerek, sürüm oluşturmayı göze çarpmayan tutarız ve geriye dönük uyumluluğu desteklemek için kolay degradasyona izin veririz (örneğin, görünümün v5'i yoksa, biz görünümün v4'ünü oluştur).


8

Bir sürüm açıkça talep edilmiyorsa neden belirli bir sürüme yönlendirmek istediğinizden emin değilim . Görünüşe göre, açıkça bir sürüm istenmiyorsa sunulan varsayılan bir sürümü tanımlamak istiyorsunuz. Ayrıca, sürümleri URL yapısının dışında tutmanın sürüm oluşturmayı desteklemenin daha temiz bir yolu olduğunu da kabul ediyorum.

Utanmaz fiş: Versionist bu kullanım durumlarını (ve daha fazlasını) destekler.

https://github.com/bploetz/versionist


2

Ryan Bigg yanıtı benim için çalıştı.

Sorgu parametrelerini yeniden yönlendirme yoluyla da tutmak istiyorsanız, bunu şu şekilde yapabilirsiniz:

match "*path", to: redirect{ |params, request| "/api/v2/#{params[:path]}?#{request.query_string}" }

2

Bunu bugün uyguladık ve RailsCasts - REST API Sürümleme için 'doğru yol' olduğuna inandığım şeyi buldum . Çok basit. Böylece bakımı yapılabilir. Çok etkili.

Ekle lib/api_constraints.rb(vnd.example öğesini değiştirmek zorunda bile değilsiniz.)

class ApiConstraints
  def initialize(options)
    @version = options[:version]
    @default = options[:default]
  end

  def matches?(req)
    @default || req.headers['Accept'].include?("application/vnd.example.v#{@version}")
  end
end

config/routes.rbÖyle kurulum

require 'api_constraints'

Rails.application.routes.draw do

  # Squads API
  namespace :api do
    # ApiConstaints is a lib file to allow default API versions,
    # this will help prevent having to change link names from /api/v1/squads to /api/squads, better maintainability
    scope module: :v1, constraints: ApiConstraints.new(version:1, default: true) do
      resources :squads do
        # my stuff was here
      end
    end
  end

  resources :squads
  root to: 'site#index'

Denetleyicinizi düzenleyin (ör. /controllers/api/v1/squads_controller.rb)

module Api
  module V1
    class SquadsController < BaseController
      # my stuff was here
    end
  end
end

Sonra uygulamanıza tüm bağlantıları değiştirebilir /api/v1/squadsiçin /api/squadsve yapabilecekleriniz KOLAYCA hatta bağlantıları değiştirmek zorunda kalmadan yeni API sürümleri uygulamak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.