У меня есть движок Rails 3, который предоставляет маршруты API для примерно 20 контроллеров. Эти контроллеры представляют несколько различных ресурсов на разных уровнях гнездования и покрываются более чем 500 rspec-тестами. API версируется в версии v1 с использованием пространств имен и ограничения маршрутизации на основе заголовка версии с по умолчанию до v1. Это система управления версиями, описанная в большом количестве сообщений в блогах и, по-видимому, является лучшей практикой.
Что ни одна из этих сообщений в блогах не описывает, как вы фактически управляете развертыванием новой версии. Я должен внести изменения в выход одного контроллера. Это изменение влияет на JSON-ответ объекта, изменяя структуру одного из значений JSON. Это вызовет перерывы в индексе, покажет и отредактирует представления для этого контроллера.
Очевидно, что я могу скопировать все app/api/v1
в app/api/v2
[1]. Затем я могу сделать свое единственное изменение в моем новом сериализаторе v2. У меня теперь есть много дублированного кода для версии 2 API, которая практически не меняла никаких изменений. Мне нужно поддерживать код в двух местах. Вероятно, мне придется использовать весь комплект rspec на контроллерах версии 2, а также на версии 1 с небольшим количеством дополнительных тестов для сериализатора v2. Это звучит как ужасная идея. Мы могли бы иметь несколько контроллеров stub v2 для каждого неизмененного контроллера в пространстве имен v1, которое наследуется от контроллера v1. Это тоже не очень приятно.
Лучший вариант, о котором я могу думать, - это иметь один контроллер (в данном случае, вероятно, только один сериализатор) внутри моего API v2, с некоторой магией маршрутизации, чтобы проверить, существует ли контроллер для требуемой версии и отступить через предыдущие версии, пока не найдет его. Версия сериализатора также должна иметь аналогичную магию, чтобы проверить, существует ли она для этой версии и отпадает, пока она ее не найдет. Это вводит минимальный дополнительный код и не мгновенно удваивает продолжительность моего набора тестов. Это потребовало бы возможности подключить функцию непосредственно к логике маршрутизации рельсов, прежде чем она сможет вернуть 404 для моих отсутствующих контроллеров v2. Возможно, я мог бы анализировать пространства имен для всех контроллеров на основе файловой системы и генерировать маршруты во время загрузки rails с помощью резервных копий, но было бы трудно управлять явным удалением маршрутов из предыдущей версии API.
Кажется, что нам нужно будет продолжать делать это для каждого неаддитивного изменения функционального/выходного формата вплоть до того, что каждая предыдущая версия устарела и удалена. У нас есть дополнительный неизданный API, состоящий из ~ 75 контроллеров, охваченных спецификациями ~ 4000. Что происходит, когда мы начинаем задокументировать и освободить их?
Помимо внесения изменений в API-интерфейс, который невозможен по скорости, которую мы выпускаем, как это делают другие люди? Возможно ли, что идея выше? Есть ли лучший способ?
[1] Проблема первая. Мы используем ActiveModel:: Сериализаторы для создания ответов JSON. ActiveModel:: Сериализаторы не поддерживает API-версию версии, хотя, кажется, существует способ обхода этого, используя ruby волшебство, чтобы выбрать правильный класс.