Создание версий веб-сервисов 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, увеличьте:
- ОСНОВНАЯ версия, когда вы делаете несовместимые изменения API,
- Версия MINOR, когда вы добавляете функциональность обратно-совместимым способом, и
- Версия PATCH, когда вы делаете обратно совместимые исправления ошибок.
Дополнительные метки для предварительной версии и метаданных сборки доступны как расширения формата MAJOR.MINOR.PATCH.
Единственная версия, которая имеет отношение к управлению версиями конечной точки REST, - это ОСНОВНАЯ версия, потому что все изменения MINOR и PATCH должны быть обратно совместимы.
Чтобы ответить на ваш вопрос:
Используйте только основные номера версий в REST URI. Остальное - деталь реализации с точки зрения REST.
Итак, ваш прото сервис будет:
rpc MerchantGet (MerchantRequest) returns (MerchantResponse) {
option (google.api.http) = {
get: "/v1/myapi/merchant/{MerchantID}"
};
}