Управление версиями API в веб-приложениях - PullRequest
6 голосов
/ 23 июля 2011

В настоящее время я занимаюсь разработкой версионного API для нового веб-сайта.Я понимаю, как использовать пространство имен для маршрутов, но я застрял в наилучшем способе реализации версионных методов в модели.

В примерах кода ниже используется структура rails, но принцип работы должен быть согласован в большинстве веб-сайтов.frameworks.

Маршруты в настоящее время выглядят примерно так:

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

И контроллер:

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

Итак, очевидно, мы просто выставляем атрибуты, доступные в Product здесьЭто решение прекрасно работает, если у вас будет только одна версия API.Что происходит, когда вы хотите выпустить V2, а V2 необходимо переопределить способ отображения имени продукта (при сохранении обратной совместимости с V1 - по крайней мере, в краткосрочной перспективе)?

Насколько я понимаю, у вас естьпара опций ...

  1. Немедленно прекратить поддержку V1 и справиться с последствиями (наихудшее из возможных решений)
  2. Вы начинаете переопределять методы to_ [format] (я довольноконечно, вы делаете это с помощью as_ [format], но это не имеет значения) для добавления нового атрибута ... name_2 - это выглядит одинаково глупо
  3. Реализация некоторого прокси-класса, который отвечает за показ толькометоды, которые мы ищем
  4. Позволяет представлениям создавать какой-то хэш, который контролируются версионными контроллерами и вызывают to[format] on ...

Три и четыре - единственные, которыеЯ могу думать, что в этом есть какой-то смысл ... Три будут выглядеть примерно так:

# 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

Что делали другие люди в прошлом?

Ответы [ 2 ]

6 голосов
/ 23 июля 2011

Вместо одного приложения, обслуживающего V1, V2 и V ... вы развертываете одно приложение для каждой версии.Одно приложение ответит на api.domain.com/v1, затем другое приложение ответит на api.domain.com/v2 и т. Д.

Таким образом, сервис-ориентированные приложения лучше всего организованы, каждый сервисдолжно быть изолированным, независимое развертывание.

Обслуживание всех версий из одного приложения отрицательно сказывается на цели сервис-ориентированного проектирования, поскольку каждый раз, когда вы вносите изменения в один сервис, вам нужно будет тестировать и развертывать для всех.

0 голосов
/ 14 мая 2012

Я думаю, что вы могли бы чрезмерно проектировать свой API, если вы планируете создавать отдельные версии.Пока вы никогда не удаляете URL-адреса и свойства в будущем, старые клиенты могут продолжать использовать ваш API.Просто используйте v1, v2 и т. Д. Как способ разделения клиентов, когда API работают над ошибкой или извращением.

Если вы меняете базовую архитектуру за пределы того, что может поддерживать исходный API, тогда я согласенвам нужно создать прокси для старой платформы, если вы планируете поддерживать старых клиентов.Для новой системы я бы создал новый сервер конечных точек, как предлагает @Nerian.

...