Создание версий веб-сервисов REST поверх gRPC

Я реализовал службу API, используя gRPC с буферами протокола, а затем использовал grpc-gateway, чтобы представить его как набор веб-сервисов REST.

Теперь я подхожу к тому, что мне приходится поддерживать разные версии API, и я застрял.

В моем прото-файле у меня есть такой обработчик, например, определенный

rpc MerchantGet (MerchantRequest) returns (MerchantResponse) {
    option (google.api.http) = {
        get: "/v1.1.0/myapi/merchant/{MerchantID}"
    };
}

В моем коде Go, конечно, у меня есть функция, MerchantGet, которому GET действия по /v1.1.0/myapi/merchant/{MerchantID} сопоставлены.

Теперь, скажем, я хочу добавить больше функциональности к MerchantGet метод и выпустить новую версию. Я намерен поддерживать обратную совместимость в соответствии со Спецификацией семантического управления версиями, поэтому, если я правильно понимаю, это означает, что я могу внести базовые изменения в свой MerchantGet метод и пусть он заменяет старый метод, если он не требует других входных данных от третьей стороны (MerchantRequest) или измените ответ, отправленный третьему лицу (MerchantResponse) кроме добавления дополнительных полей в конец ответа. (Поправьте меня, если я ошибаюсь в этом предположении).

Мой вопрос: как мне написать прото-обработчики для обслуживания метода на конечных точках разных версий? Один вариант, который пришел в голову, выглядел бы следующим образом:

rpc MerchantGet (MerchantRequest) returns (MerchantResponse) {
    option (google.api.http) = {
        get: "/v1.6.0/myapi/merchant/{MerchantID}"
        additional_bindings {
            get: "/v1.5.0/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.4.2/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.4.1/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.4.0/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.3.0/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.2.0/myapi/merchant/{MerchantID}"
        }
        additional_bindings {
            get: "/v1.1.0/myapi/merchant/{MerchantID}"
        }
    };
}

Но, конечно, это не может быть идиоматическим способом достижения этого? Это, конечно, не очень элегантно, так как с каждой новой минорной версией или патчем мне придется расширять эти additional_bindings для каждого из моих методов (выше я просто использую один метод в качестве примера).

1 ответ

Решение

Из спецификации SemVer:

Учитывая номер версии MAJOR.MINOR.PATCH, увеличьте:

  1. ОСНОВНАЯ версия, когда вы делаете несовместимые изменения API,
  2. Версия MINOR, когда вы добавляете функциональность обратно-совместимым способом, и
  3. Версия PATCH, когда вы делаете обратно совместимые исправления ошибок.

Дополнительные метки для предварительной версии и метаданных сборки доступны как расширения формата MAJOR.MINOR.PATCH.

Единственная версия, которая имеет отношение к управлению версиями конечной точки REST, - это ОСНОВНАЯ версия, потому что все изменения MINOR и PATCH должны быть обратно совместимы.

Чтобы ответить на ваш вопрос:
Используйте только основные номера версий в REST URI. Остальное - деталь реализации с точки зрения REST.

Итак, ваш прото сервис будет:

rpc MerchantGet (MerchantRequest) returns (MerchantResponse) {
    option (google.api.http) = {
        get: "/v1/myapi/merchant/{MerchantID}"
    };
}
Другие вопросы по тегам