La forma original de esta respuesta es muy diferente, y se puede encontrar aquí . Solo prueba de que hay más de una forma de pelar un gato.
He actualizado la respuesta desde entonces para usar espacios de nombres y usar redireccionamientos 301, en lugar del valor predeterminado de 302. Gracias a pixeltrix y Bo Jeanes por sus comentarios.
Es posible que desee usar un casco realmente fuerte porque esto le dejará boquiabierto .
La API de enrutamiento Rails 3 es súper malvada. Para escribir las rutas para su API, según sus requisitos anteriores, solo necesita esto:
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 tu mente sigue intacta después de este punto, déjame explicarte.
Primero, llamamos namespace
cuál es súper útil para cuando quieres un montón de rutas con alcance a una ruta específica y módulo que tengan un nombre similar. En este caso, queremos que todas las rutas dentro del bloque namespace
tengan alcance para los controladores dentro del Api
módulo y todas las solicitudes a rutas dentro de esta ruta tendrán el prefijo api
. Solicitudes como /api/v2/users
, ¿sabes?
Dentro del espacio de nombres, definimos dos espacios de nombres más (¡woah!). Esta vez estamos definiendo el espacio de nombres "v1", por lo que todas las rutas para los controladores de aquí estarán dentro del V1
módulo en el interior del Api
módulo: Api::V1
. Al definir resources :users
dentro de esta ruta, el controlador se ubicará en Api::V1::UsersController
. Esta es la versión 1, y llega allí haciendo solicitudes como /api/v1/users
.
La versión 2 es sólo una pequeña poco diferente. En lugar de que el controlador esté sirviendo Api::V1::UsersController
, ahora está en Api::V2::UsersController
. Llegas allí haciendo solicitudes como /api/v2/users
.
A continuación, match
se utiliza a. Esto coincidirá con todas las rutas API que van a cosas como /api/v3/users
.
Esta es la parte que tuve que buscar. La :to =>
opción le permite especificar que una solicitud específica se debe redirigir a otro lugar, lo sabía, pero no sabía cómo hacer que se redirigiera a otro lugar y pasar una parte de la solicitud original junto con ella. .
Para hacer esto, llamamos al redirect
método y le pasamos una cadena con un %{path}
parámetro interpolado especial . Cuando llega una solicitud que coincide con esta final match
, interpolará el path
parámetro en la ubicación %{path}
dentro de la cadena y redirigirá al usuario a donde debe ir.
Finalmente, usamos otro match
para enrutar todos los caminos restantes con el prefijo /api
y redirigirlos a ellos /api/v2/%{path}
. Esto significa que las solicitudes como /api/users
irán a /api/v2/users
.
No pude averiguar cómo llegar /api/asdf/users
a una coincidencia, porque ¿cómo se determina si se supone que es una solicitud /api/<resource>/<identifier>
o /api/<version>/<resource>
?
De todos modos, esto fue divertido de investigar y espero que te ayude.
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.
Un par de cosas para agregar:
Su coincidencia de redireccionamiento no funcionará para ciertas rutas: el
*api
parámetro es codicioso y se tragará todo, por ejemplo/api/asdf/users/1
, redireccionará a/api/v2/1
. Sería mejor usar un parámetro regular como:api
. Es cierto que no coincidirá con casos como,/api/asdf/asdf/users/1
pero si tiene recursos anidados en su API, es una mejor solución.Ryan ¿POR QUÉ NO TE GUSTA
namespace
? :-), p.ej:Que tiene el beneficio adicional de las rutas nombradas versionadas y genéricas. Una nota adicional: la convención cuando se usa
:module
es usar notación de subrayado, por ejemplo:api/v1
no 'Api :: V1'. En un momento, este último no funcionó, pero creo que se solucionó en Rails 3.1.Además, cuando lance la versión 3 de su API, las rutas se actualizarán así:
Por supuesto, es probable que su API tenga diferentes rutas entre versiones, en cuyo caso puede hacer esto:
fuente
/api/asdf/users?
, así como/api/users/1
? No pude entender eso en mi respuesta actualizada, así que pensé que sabrías de alguna maneraSi es posible, sugeriría repensar sus URL para que la versión no esté en la URL, sino que se coloque en el encabezado acepta. Esta respuesta de desbordamiento de pila va bien:
¿Mejores prácticas para el control de versiones de API?
y este enlace muestra exactamente cómo hacerlo con el enrutamiento de rieles:
http://freelancing-gods.com/posts/versioning_your_ap_is
fuente
No soy un gran fanático del versionado por rutas. Creamos VersionCake para admitir una forma más fácil de versiones de API.
Al incluir el número de versión de API en el nombre de archivo de cada una de nuestras vistas respectivas (jbuilder, RABL, etc.), mantenemos la versión discreta y permitimos una fácil degradación para admitir la compatibilidad con versiones anteriores (por ejemplo, si la v5 de la vista no existe, nosotros render v4 de la vista).
fuente
No estoy seguro de por qué desea redirigir a una versión específica si no se solicita explícitamente una versión. Parece que simplemente desea definir una versión predeterminada que se sirve si no se solicita explícitamente ninguna versión. También estoy de acuerdo con David Bock en que mantener las versiones fuera de la estructura de URL es una forma más limpia de admitir el control de versiones.
Plug descarado: Versionist admite estos casos de uso (y más).
https://github.com/bploetz/versionist
fuente
La respuesta de Ryan Bigg funcionó para mí.
Si también desea mantener los parámetros de consulta a través de la redirección, puede hacerlo así:
fuente
Implementé esto hoy y encontré lo que creo que es la "forma correcta" en RailsCasts - REST API Versioning . Tan sencillo. Tan mantenible. Tan efectivo
Agregar
lib/api_constraints.rb
(ni siquiera tiene que cambiar vnd.example).Configurar
config/routes.rb
asíEdite su controlador (es decir
/controllers/api/v1/squads_controller.rb
)Luego puede cambiar todos los enlaces de su aplicación de
/api/v1/squads
a/api/squads
e implementar FÁCILMENTE nuevas versiones de API sin siquiera tener que cambiar los enlacesfuente