A forma original desta resposta é muito diferente e pode ser encontrada aqui . Apenas prova de que há mais de uma maneira de esfolar um gato.
Atualizei a resposta desde então para usar namespaces e redirecionamentos 301 - em vez do padrão 302. Agradecemos a pixeltrix e Bo Jeanes pela solicitação sobre essas coisas.
Você pode usar um capacete muito forte, porque isso vai surpreender sua mente .
A API de roteamento do Rails 3 é super maliciosa. Para escrever as rotas para sua API, conforme seus requisitos acima, você precisa apenas disso:
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
Se sua mente ainda estiver intacta após esse ponto, deixe-me explicar.
Primeiro, chamamos de namespace
que é super útil quando você deseja um monte de rotas com escopo definido para um caminho e módulo específicos com nomes semelhantes. Nesse caso, queremos que todas as rotas dentro do bloco namespace
tenham o escopo definido para os controladores dentro do Api
módulo e todas as solicitações de caminhos dentro dessa rota serão prefixadas api
. Pedidos como /api/v2/users
, você sabe?
Dentro do espaço para nome, definimos mais dois espaços para nome (woah!). Desta vez estamos definindo o namespace "v1", de modo que todas as rotas para os controladores aqui vai estar dentro do V1
módulo dentro do Api
módulo: Api::V1
. Ao definir resources :users
dentro dessa rota, o controlador estará localizado em Api::V1::UsersController
. Esta é a versão 1, e você chega lá fazendo solicitações como /api/v1/users
.
A versão 2 é apenas uma pequena pouco diferente. Em vez de o controlador atender Api::V1::UsersController
, ele está agora Api::V2::UsersController
. Você chega lá fazendo pedidos como /api/v2/users
.
Em seguida, a match
é usado. Isso corresponderá a todas as rotas da API que vão para coisas como /api/v3/users
.
Esta é a parte que eu tive que procurar. A :to =>
opção permite que você especifique que uma solicitação específica deve ser redirecionada para outro lugar - eu sabia disso -, mas não sabia como redirecioná-la para outro lugar e passar uma parte da solicitação original junto com ela .
Para fazer isso, chamamos o redirect
método e passamos uma string com um %{path}
parâmetro interpolado especial . Quando chega uma solicitação que corresponde a esta final match
, ele interpola o path
parâmetro no local %{path}
dentro da string e redireciona o usuário para onde eles precisam ir.
Finalmente, usamos outro match
para rotear todos os caminhos restantes prefixados /api
e redirecioná-los para /api/v2/%{path}
. Isso significa que solicitações como /api/users
irão para /api/v2/users
.
Eu não conseguia descobrir como obter /api/asdf/users
para corresponder, porque como é possível determinar se isso é suposto ser um pedido para /api/<resource>/<identifier>
ou /api/<version>/<resource>
?
Enfim, foi divertido pesquisar e espero que ajude você!
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.
Algumas coisas a acrescentar:
Sua correspondência de redirecionamento não funcionará em determinadas rotas - o
*api
parâmetro é ganancioso e engole tudo, por exemplo/api/asdf/users/1
, redireciona para/api/v2/1
. Você seria melhor usando um parâmetro regular:api
. É certo que não corresponderá a casos como o/api/asdf/asdf/users/1
caso, mas se você tiver recursos aninhados na sua API, é uma solução melhor.Ryan POR QUE VOCÊ NÃO GOSTA
namespace
? :-), por exemplo:Que possui o benefício adicional de rotas nomeadas com versão e genéricas. Uma observação adicional - a convenção ao usar
:module
é usar notação de sublinhado, por exemplo:api/v1
não 'Api :: V1'. Em um ponto, o último não funcionou, mas acredito que foi corrigido no Rails 3.1.Além disso, quando você libera a v3 da sua API, as rotas são atualizadas da seguinte maneira:
Obviamente, é provável que sua API tenha rotas diferentes entre versões. Nesse caso, você pode fazer isso:
fonte
/api/asdf/users?
, bem como/api/users/1
? Eu não poderia descobrir isso na minha resposta atualizado, por isso imaginei que você poderia saber de uma maneiraSe possível, sugiro repensar seus URLs para que a versão não esteja no URL, mas seja colocada no cabeçalho Accept. Essa resposta de estouro de pilha é muito útil:
Práticas recomendadas para controle de versão da API?
e este link mostra exatamente como fazer isso com o roteamento de trilhos:
http://freelancing-gods.com/posts/versioning_your_ap_is
fonte
Eu não sou um grande fã de versionamento por rotas. Criamos o VersionCake para oferecer suporte a uma forma mais fácil de versionamento da API.
Ao incluir o número da versão da API no nome do arquivo de cada uma de suas respectivas visualizações (jbuilder, RABL, etc), mantemos a versão discreta e permitimos degradação fácil para suportar a compatibilidade com versões anteriores (por exemplo, se a v5 da visualização não existir, nós renderizar v4 da visualização).
fonte
Não sei por que você deseja redirecionar para uma versão específica se uma versão não for solicitada explicitamente. Parece que você simplesmente deseja definir uma versão padrão que será exibida se nenhuma versão for solicitada explicitamente. Também concordo com David Bock que manter as versões fora da estrutura da URL é uma maneira mais limpa de oferecer suporte a versões.
Plugue descarado: o versionista suporta esses casos de uso (e mais).
https://github.com/bploetz/versionist
fonte
A resposta de Ryan Bigg funcionou para mim.
Se você também deseja manter os parâmetros de consulta através do redirecionamento, pode fazê-lo assim:
fonte
Implementou isso hoje e encontrou o que eu acredito ser o 'caminho certo' no RailsCasts - REST API Versioning . Tão simples. Tão sustentável. Tão eficaz.
Adicionar
lib/api_constraints.rb
(nem precisa alterar vnd.example.)Configure
config/routes.rb
assimEdite seu controlador (ie
/controllers/api/v1/squads_controller.rb
)Em seguida, você pode alterar todos os links em seu aplicativo de
/api/v1/squads
para/api/squads
e você pode facilmente implementar novas versões de API sem precisar alterar os linksfonte