HTTP-клиент на Retrofit
Пакет ru.bgcrm.util.api содержит штатный механизм вызова внешних HTTP API из ERP.
Разработчик описывает контракт интерфейсом Retrofit, помечает его @Api, а
ApiClientFactory собирает синхронный клиент с общей конфигурацией, авторизацией,
ограничением частоты, Circuit Breaker, логированием и телеметрией.
Новый код следует писать на этом механизме. Старый стек на основе
ru.ufanet.retrofit.BasicClient помечен @Deprecated и закрыт от расширения
архитектурным тестом.
Долгие пользовательские операции выполняйте по схеме
асинхронной работы с внешними сервисами:
после commit исходной команды, через AsyncWorker, без удержания JDBC-соединения
во время сетевого ожидания.
Что делает фабрика
При каждом вызове ApiClientFactory.getClient() фабрика:
-
читает
@Apiи секциюapi.<name>из глобальной конфигурации ERP; -
выбирает JSON- или XML-маппер Jackson;
-
создаёт OkHttp-клиент, его пул соединений и Dispatcher;
-
подключает перехватчики, авторизацию и дополнительные расширения;
-
добавляет Rate Limiter, Circuit Breaker и синхронный адаптер вызова;
-
возвращает реализацию интерфейса, созданную Retrofit.
Фабрика не кэширует созданный Retrofit-прокси. Пулы и компоненты
Resilience4j кэшируются отдельно по @Api.name. Поэтому один и тот же экземпляр
интерфейса продолжает работать со старой конфигурацией, а новое значение настроек
подхватывается только при следующем вызове getClient().
|
Быстрый старт
Описать контракт
import retrofit2.http.GET
import retrofit2.http.Path
import ru.bgcrm.util.api.annotation.Api
@Api(name = "catalog")
interface CatalogApi {
@GET("api/products/{id}")
fun getProduct(@Path("id") id: Long): ProductDto
}
data class ProductDto(
val id: Long,
val name: String
)
@Api имеет три параметра:
| Параметр | По умолчанию | Назначение |
|---|---|---|
|
нет |
Ключ секции |
|
|
Основной формат тела: |
|
|
Модель JSON-ошибки. Должна наследовать |
Методы используют стандартные аннотации Retrofit: @GET, @POST, @Path,
@Query, @Body, @Header и другие. Они возвращают конечный тип, а не
retrofit2.Call<T>: вызов выполняется синхронно в потоке вызывающего кода.
Добавить конфигурацию
api.catalog.name=Каталог товаров
api.catalog.url=https://catalog.example.test/
api.catalog.auth.type=STATIC_TOKEN
api.catalog.auth.header=Authorization
api.catalog.auth.token=<service-token>
api.catalog.http.connectTimeout=10000
api.catalog.http.readTimeout=10000
api.catalog совпадает с @Api(name = "catalog"). Base URL должен быть
абсолютным и оканчиваться /, как требует Retrofit.
Полный перечень параметров приведён в разделе конфигурации.
Получить и вызвать клиент
import ru.bgcrm.context.core.ServerContext
import ru.bgcrm.context.core.getService
import ru.bgcrm.util.api.factory.ApiClientFactory
class CatalogService(
apiClientFactory: ApiClientFactory = ServerContext.getService()
) {
private val api = apiClientFactory.getClient(CatalogApi::class.java)
fun getProduct(id: Long): ProductDto = api.getProduct(id)
}
Перегрузка getClient(CatalogApi::class.java, url) подменяет только base URL.
Остальные настройки по-прежнему берутся из api.catalog.
Состав пакета
| Область | Ответственность |
|---|---|
|
Описание API, чтение настроек и сборка Retrofit/OkHttp-клиента. |
|
Выбор провайдера авторизации, получение и хранение внешних токенов. |
|
Синхронное выполнение вызова и декораторы Rate Limiter/Circuit Breaker. |
|
Кэшируемые пулы, Dispatcher, компоненты Resilience4j и их MBean. |
|
Подключение собственных конвертеров; встроенная обёртка SOAP 1.1. |
|
Телеметрия, HTTP-логирование, методные теги и внешние перехватчики. |
|
Ошибки транспорта и отдельная обёртка над Rate Limiter для ручных сценариев. |
Следующие разделы
-
Конфигурация — все ключи, значения по умолчанию и обновление компонентов.
-
Авторизация — встроенные режимы,
@NoAuth, внешний токен и свой провайдер. -
Выполнение запроса — порядок обработки, ответы, ошибки, SOAP, метрики и JMX.
-
Расширение и ограничения — собственные конвертеры, перехватчики, теги и известные особенности реализации.