2011-07-23 17 views
6

Actualmente estoy en el proceso de diseño de una API versionada para un nuevo sitio web. Entiendo cómo crear espacios de nombre de las rutas, pero estoy atascado en la mejor forma de implementar métodos versionados dentro de un modelo.Control de versiones de API en aplicaciones web

Los siguientes ejemplos de código están utilizando el marco de raíles, pero el principio de la cuestión debe ser coherente entre la mayoría de los marcos web.

Las rutas actualmente se ven algo como:

MyApp::Application.routes.draw do 
    namespace :api do 
    namespace :v1 do 
     resources :products, :only => [:index, :show] 
    end 
    end 
end 

y el controlador:

class Api::V1::ProductsController < V1Controller 
    respond_to :json, :xml 

    def index 
    respond_with @products = Product.scoped 
    end 

    def show 
    respond_with @product = Product.find(params[:id]) 
    end 
end 

Así que, obviamente, sólo estamos exponiendo los atributos disponibles en producto aquí, esta solución funciona muy bien si usted' Solo tendremos una versión de la API. ¿Qué sucede cuando desea liberar V2 y V2 necesita volver a implementar la forma en que se muestra el nombre del producto (manteniendo la compatibilidad con V1 al revés, al menos en el corto plazo)?

Por lo que yo veo que tiene un par de opciones de soporte ...

  1. gota para V1 inmediatamente y lidiar con las consecuencias (peor solución posible)
  2. Se comienza reemplazando el to_ [formato ] methods (estoy bastante seguro de que harías esto con as_ [format] pero eso está al lado del punto) para incluir un nuevo atributo ... name_2 - esto parece igualmente tonto
  3. Implementa algún tipo de clase proxy que sea responsable de exponer solo los métodos que estamos buscando
  4. Let vistas manejan la creación de algún tipo de hash que los controladores y versionados llaman to[format] en ...

tres y cuatro son los únicos que realmente hace que se me ocurre ningún tipo de sentido ... Tres vería algo como:

# model 
class Api::V1::Product < Struct.new(:product) 
    def to_json 
    attributes.to_json 
    end 

    def to_xml 
    attributes.to_xml 
    end 

private 
    def attributes 
    {:name => product.name} # add all the attributes you want to expose 
    end 
end 

# Controller 
class Api::V1::ProductsController < V1Controller 
    respond_to :json, :xml 

    def show 
    respond_with @product = Api::V1::Product.new(Product.find(params[:id])) 
    end 
end 

¿Qué han hecho otras personas en el pasado?

Respuesta

6

En lugar de una aplicación para V1 y V2 y V ... despliega una aplicación para cada versión. Una aplicación responderá a api.domain.com/v1, luego otra aplicación responderá a api.domain.com/v2 y así sucesivamente.

Así es como las aplicaciones orientadas al servicio están mejor organizadas, cada servicio debe ser aislado, una implementación independiente.

Al servir todas las versiones desde una sola aplicación, se frustra el propósito del diseño orientado al servicio, ya que cada vez que realice un cambio en un servicio deberá probarlo e implementarlo para todos.

+0

Esta es una solución realmente buena, algo en lo que no había pensado ... – Coop

-1

Creo que es posible que esté sobre-ingeniería de su API si planea crear distintas versiones. Siempre que nunca elimine las URL y las propiedades en el futuro, los clientes antiguos pueden continuar usando su API. Solo use v1, v2, etc. como una manera de segregar clientes cuando las API están trabajando en torno a un error o peculiaridad.

Si está cambiando la arquitectura subyacente más allá de lo que la API original puede admitir, entonces acepto que deberá crear un proxy para la plataforma anterior si planea admitir clientes antiguos. Para el nuevo sistema, crearía un servidor de punto final completamente nuevo como sugiere @Nerian.

Cuestiones relacionadas