Как применить управление версиями проверки к моделям Rails API?

#ruby-on-rails #rails-api #api-versioning

#ruby-on-rails #rails-api #api-управление версиями

Вопрос:

Я искал информацию о создании API-интерфейсов Rails и о том, как правильно применять некоторые версии для проверки моделей.

Предположим, что есть модель и маршрут, подобные этим:

 class Person < ApplicationRecord
  validates :name, presence: true
end
  
 namespace :v1
  resources :people
end
  

Итак, моя модель проверяет name , присутствует ли она.

Но, если я хочу выпустить новую версию своего API с новой проверкой Person , чтобы сделать, например, job поле обязательным, как это:

 class Person < ApplicationRecord
  validates :name, presence: true
  validates :job, presence: true
end
  

Если я сделаю это таким образом, я бы сломал свою конечную точку V1. Итак, есть ли хорошая практика, чтобы сделать это, не нарушая мою предыдущую конечную точку V1? Или я должен удалить эти проверки из модели и сделать это на уровне параметров запроса?

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

Ответ №1:

Самый простой способ добиться этого — использовать :on option для ваших проверок и выполнять контекстные проверки, например

 class Person < ApplicationRecord
  validates :name, presence: true
  validates :job, presence: true, on: :v2
end
  

Затем вы можете использовать person.valid? в своей конечной точке v1 и person.valid?(:v2) в конечной точке v2.

Но это решение достаточно хорошо только для простых сценариев, оно не масштабируется в долгосрочных или более сложных приложениях.

Лучшим решением было бы извлечь логику проверки для формирования объектов, созданных из ваших параметров, и иметь отдельные объекты формы для каждой версии ваших конечных точек, которые содержат некоторые критические изменения, например:

 class PersonV1Form
  include ActiveModel::Validations

  attr_accessor :name, :job
  validates :name, presence: true

  def initialize(params = {})
    @name = params[:name]
    @job = params[:job]
  end
end

class PersonV2Form
  include ActiveModel::Validations

  attr_accessor :name, :job
  validates :name, :job, presence: true

  def initialize(params = {})
    @name = params[:name]
    @job = params[:job]
  end
end
  

Затем в ваших контроллерах вы можете просто проверять объекты формы, прежде чем использовать их для подачи вашей модели:

 module V1
  class PeopleController < ApplicationController
    def create
      person = PersonV1Form.new(params[:person])
      if person.valid?
        # ...
      end
    end
  end
end

module V2
  class PeopleController < ApplicationController
    def create
      person = PersonV2Form.new(params[:person])
      if person.valid?
        # ...
      end
    end
  end
end