Stripe처럼 API를 버전하려고합니다. 아래는 최신 API 버전이 2입니다.
/api/users
에 301을 반환 /api/v2/users
/api/v1/users
버전 1에서 200의 사용자 색인을 리턴합니다.
/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
답변
이 답변의 원래 형식은 크게 다르며 여기에서 찾을 수 있습니다 . 고양이를 피부에 바르는 방법이 두 가지 이상 있다는 것을 증명하십시오.
네임 스페이스를 사용하고 기본값 302 대신 301 리디렉션을 사용하기 때문에 답변을 업데이트했습니다.
당신은 당신의 마음 을 날려 버릴 것이기 때문에 당신은 정말 강한 헬멧 을 착용하고 싶을 수도 있습니다 .
Rails 3 라우팅 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 match
가 사용됩니다. 이것은와 같은 모든 API 경로와 일치합니다 /api/v3/users
.
이것은 내가 찾아야 할 부분입니다. 이 :to =>
옵션을 사용하면 특정 요청을 다른 곳으로 리디렉션해야한다고 지정할 수 있습니다. .
이를 위해 redirect
메소드를 호출하고 특수 보간 %{path}
매개 변수가 있는 문자열을 전달합니다 . 이 final과 일치하는 요청이 들어 오면 매개 변수를 문자열 내부의 위치로 match
보간 하고 사용자를 필요한 곳으로 리디렉션합니다.path
%{path}
마지막으로 다른 match
경로를 사용하여 접두사가있는 나머지 모든 경로를 라우팅 /api
하고로 리디렉션합니다 /api/v2/%{path}
. 이는와 같은 요청 /api/users
이로 이동 함을 의미합니다 /api/v2/users
.
내가 얻는 방법을 알아낼 수없는 /api/asdf/users
그가에 요청 있어야하는 경우 당신은 어떻게 결정 않기 때문에, 일치 /api/<resource>/<identifier>
또는 /api/<version>/<resource>
?
어쨌든, 이것은 연구하기에 재미 있었고 나는 그것이 당신에게 도움이되기를 바랍니다!
답변
몇 가지 추가 할 사항 :
리디렉션 경로가 특정 경로에서는 작동하지 않습니다. *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
not ‘Api :: V1’). 언젠가 후자가 작동하지 않았지만 Rails 3.1에서 수정되었다고 생각합니다.
또한 API v3을 릴리스하면 경로가 다음과 같이 업데이트됩니다.
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에 없지만 accepts 헤더에 들어가도록 URL을 다시 생각하는 것이 좋습니다. 이 스택 오버플로 답변은 잘 들어갑니다.
이 링크는 레일 라우팅을 통해이를 수행하는 방법을 정확하게 보여줍니다.
답변
나는 노선별로 버전 관리를 좋아하지 않습니다. 보다 쉬운 API 버전 관리 를 지원하기 위해 VersionCake 를 구축했습니다 .
각각의 각 뷰 (jbuilder, RABL 등)의 파일 이름에 API 버전 번호를 포함하여 버전 관리를 방해하지 않고 이전 버전과의 호환성을 지원하기 위해 쉽게 저하되도록합니다 (예 : 뷰의 v5가 존재하지 않는 경우 뷰의 v4 렌더링).
답변
버전이 명시 적으로 요청되지 않은 경우 왜 특정 버전 으로 리디렉션 해야하는지 잘 모르겠습니다 . 명시 적으로 요청 된 버전이없는 경우 제공되는 기본 버전을 정의하려는 것 같습니다. 또한 URL 구조에서 버전을 유지하는 것이 버전 관리를 지원하는 더 확실한 방법이라는 David Bock에 동의합니다.
뻔뻔한 플러그 : Versionist는 이러한 사용 사례 등을 지원합니다.
답변
Ryan Bigg의 답변이 저에게 효과적이었습니다.
리디렉션을 통해 쿼리 매개 변수를 유지하려면 다음과 같이하십시오.
match "*path", to: redirect{ |params, request| "/api/v2/#{params[:path]}?#{request.query_string}" }
답변
오늘 이것을 구현하고 RailsCasts-REST API Versioning 에서 ‘올바른 방법’으로 생각되는 것을 발견했습니다 . 너무 간단합니다. 따라서 유지 관리가 가능합니다. 너무 효과적입니다.
추가 lib/api_constraints.rb
(예 : vnd.example을 변경할 필요조차 없음)
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
그렇게 설정
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'
편집 컨트롤러 (예 /controllers/api/v1/squads_controller.rb
)
module Api
module V1
class SquadsController < BaseController
# my stuff was here
end
end
end
그런 다음에서 응용 프로그램의 모든 링크를 변경할 수 있습니다 /api/v1/squads
에 /api/squads
당신은 할 수 있습니다 쉽게 도 링크를 변경하지 않고도 새로운 API 버전을 구현