La forme originale de cette réponse est très différente et peut être trouvée ici . Juste la preuve qu'il y a plus d'une façon d'écorcher un chat.
J'ai mis à jour la réponse depuis pour utiliser les espaces de noms et utiliser les redirections 301 - plutôt que la valeur par défaut de 302. Merci à pixeltrix et Bo Jeanes pour les invites sur ces choses.
Vous voudrez peut-être porter un casque vraiment solide, car cela va vous épater .
L'API de routage Rails 3 est super méchante. Pour écrire les routes de votre API, conformément à vos exigences ci-dessus, vous avez juste besoin de ceci:
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
Si votre esprit est toujours intact après ce point, laissez-moi vous expliquer.
Tout d'abord, nous appelons namespace
ce qui est très pratique lorsque vous voulez un tas de routes étendues à un chemin et un module spécifiques portant le même nom. Dans ce cas, nous voulons que toutes les routes à l'intérieur du bloc pour notre namespace
soient étendues aux contrôleurs dans le Api
module et toutes les demandes aux chemins à l'intérieur de cette route seront préfixées avec api
. Des demandes telles que /api/v2/users
, tu sais?
Dans l'espace de noms, nous définissons deux autres espaces de noms (woah!). Cette fois , nous définissons l'espace de noms « v1 », donc tous les itinéraires pour les contrôleurs ici seront à l' intérieur du V1
module à l' intérieur du Api
module de : Api::V1
. En définissant à l' resources :users
intérieur de cette route, le contrôleur sera situé à Api::V1::UsersController
. C'est la version 1, et vous y arrivez en faisant des requêtes comme /api/v1/users
.
La version 2 est seulement un petit différent bits. Au lieu que le contrôleur le servant soit à Api::V1::UsersController
, il est maintenant à Api::V2::UsersController
. Vous y arrivez en faisant des demandes comme /api/v2/users
.
Ensuite, a match
est utilisé. Cela correspondra à toutes les routes d'API qui vont à des choses comme /api/v3/users
.
C'est la partie que je devais rechercher. L' :to =>
option vous permet de spécifier qu'une demande spécifique doit être redirigée ailleurs - je le savais bien - mais je ne savais pas comment la faire rediriger vers un autre endroit et transmettre un morceau de la demande d'origine avec elle .
Pour ce faire, nous appelons la redirect
méthode et lui passons une chaîne avec un %{path}
paramètre interpolé spécial . Lorsqu'une requête correspond à cette finale match
, elle interpole le path
paramètre à l'emplacement de l' %{path}
intérieur de la chaîne et redirige l'utilisateur vers où il doit aller.
Enfin, nous en utilisons un autre match
pour acheminer tous les chemins restants préfixés par /api
et les rediriger vers /api/v2/%{path}
. Cela signifie que les demandes comme /api/users
iront à /api/v2/users
.
Je ne savais pas comment faire /api/asdf/users
correspondre, car comment déterminer si cela est censé être une demande à /api/<resource>/<identifier>
ou /api/<version>/<resource>
?
Quoi qu'il en soit, c'était amusant de rechercher et j'espère que cela vous aidera!
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.
Quelques éléments à ajouter:
Votre correspondance de redirection ne fonctionnera pas pour certaines routes - le
*api
paramètre est gourmand et engloutira tout, par exemple/api/asdf/users/1
, redirigera vers/api/v2/1
. Vous feriez mieux d'utiliser un paramètre régulier comme:api
. Certes, cela ne correspondra pas à des cas comme,/api/asdf/asdf/users/1
mais si vous avez des ressources imbriquées dans votre API, c'est une meilleure solution.Ryan POURQUOI N'AIME PAS
namespace
? :-), par exemple:Ce qui a l'avantage supplémentaire des routes nommées versionnées et génériques. Une note supplémentaire - la convention lors de l'utilisation
:module
est d'utiliser la notation de soulignement, par exemple:api/v1
pas 'Api :: V1'. À un moment donné, ce dernier n'a pas fonctionné mais je pense qu'il a été corrigé dans Rails 3.1.De plus, lorsque vous publiez la v3 de votre API, les routes seraient mises à jour comme ceci:
Bien sûr, il est probable que votre API ait des itinéraires différents entre les versions, auquel cas vous pouvez le faire:
la source
/api/asdf/users?
à dire ainsi que/api/users/1
? Je ne pouvais pas comprendre cela dans ma réponse mise à jour, alors j'ai pensé que vous pourriez connaître un moyenDans la mesure du possible, je suggérerais de repenser vos URL afin que la version ne soit pas dans l'url, mais soit placée dans l'en-tête accepte. Cette réponse de débordement de pile y va bien:
Bonnes pratiques pour la gestion des versions d'API?
et ce lien montre exactement comment faire cela avec le routage des rails:
http://freelancing-gods.com/posts/versioning_your_ap_is
la source
Je ne suis pas un grand fan du versionnage par routes. Nous avons créé VersionCake pour prendre en charge une forme plus simple de gestion des versions d'API.
En incluant le numéro de version de l'API dans le nom de fichier de chacune de nos vues respectives (jbuilder, RABL, etc.), nous gardons le contrôle de version discret et permettons une dégradation facile pour prendre en charge la rétrocompatibilité (par exemple, si la version 5 de la vue n'existe pas, nous rendu v4 de la vue).
la source
Je ne sais pas pourquoi vous souhaitez rediriger vers une version spécifique si une version n'est pas explicitement demandée. Il semble que vous souhaitiez simplement définir une version par défaut qui sera servie si aucune version n'est explicitement demandée. Je suis également d'accord avec David Bock pour dire que garder les versions hors de la structure de l'URL est un moyen plus propre de prendre en charge la gestion des versions.
Plug sans vergogne: Versionist prend en charge ces cas d'utilisation (et plus).
https://github.com/bploetz/versionist
la source
La réponse de Ryan Bigg a fonctionné pour moi.
Si vous souhaitez également conserver les paramètres de requête via la redirection, vous pouvez le faire comme suit:
la source
Je l'ai implémenté aujourd'hui et j'ai trouvé ce que je pense être la «bonne façon» sur RailsCasts - Versioning de l'API REST . Si simple. Tellement maintenable. Tellement efficace.
Ajoutez
lib/api_constraints.rb
(vous n'avez même pas besoin de changer vnd.example.)Configuration
config/routes.rb
comme çaModifiez votre contrôleur (ie
/controllers/api/v1/squads_controller.rb
)Ensuite, vous pouvez modifier tous les liens de votre application de
/api/v1/squads
à/api/squads
et vous pouvez facilement implémenter de nouvelles versions d'API sans même avoir à modifier les liensla source