Перейти к содержанию

Использование типизированных клиентов для инкапсуляции HTTP-вызовов

Существует распространённый шаблон взаимодействия с API — инкапсуляция механизма взаимодействия в отдельный сервис. У IHttpClientFactory есть основательная поддержка такого шаблона — типизированные клиенты.
Типизированный клиент — это класс, принимающий HttpClient в конструкторе и предоставляющий понятный интерфейс для потребителей, инкапсулируя детали взаимодействия с API — HTTP-методы, заголовки, пути методов и т.п.
Вот для примера типизированный клиент для API курсов обмена валют:

public class ExchangeRatesClient
{
    private readonly HttpClient _client;
    public ExchangeRatesClient(HttpClient client)
    {
        _client = client;
    }

    public async Task<string> GetLatestRates()
    {
        var response = await _client.GetAsync("latest");
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsString();
    }
}

Затем внедрим его в наш контроллер:
[ApiController]
public class ValuesController: ControllerBase
{
    private readonly ExchangeRatesClient _ratesClient;
    public ValuesController(ExchangeRatesClient ratesClient)
    {
        _ratesClient = ratesClient;
    }

    [HttpGet("values")]
    public async Task<string> GetRates()
    {
        return await _ratesClient.GetLatestRates();
    }
}

Но как тут задействован IHttpClientFactory? IHttpClientFactory создаёт HttpClient, настраивает его и внедряет в экземпляр типизированного клиента.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<ExchangeRatesClient>((HttpClient client) =>
    {
        client.BaseAddress = new Uri("https://api.exchangeratesapi.io");
        client.DefaultRequestHeaders
            .Add(HeaderNames.UserAgent, "ExchangeRateViewer");
    })
    .ConfigureHttpClient((HttpClient client) => {});//дополнительно
}

Совет

Типизированного клиента можно рассматривать как оболочку для именованного клиента. Часто это оправданный подход, так как он объединяет логику взаимодействия с удалённой службой в одном месте, а также избегает “волшебных строк”, которые используются с именованными клиентами.

Ещё один часто используемый подход — помимо реализации зарегистрировать интерфейс. Этот подход значительно упрощает тестирование.

services.AddHttpClient<IExchangeRatesClient, ExchangeRatesClient>()

Ещё один вариант — перенести конфигурацию из ConfigureServices в конструктор типизированного клиента.

public class ExchangeRatesClient
{
    private readonly HttpClient _client;
    public ExchangeRatesClient(HttpClient client)
    {
        _client = client;
        _client.BaseAddress = new Uri("https://api.exchangeratesapi.io");
        _client.DefaultRequestHeaders
            .Add(HeaderNames.UserAgent, "ExchangeRateViewer");
    }

    public async Task<string> GetLatestRates()
    {
        var response = await _client.GetAsync("latest");
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsString();
    }
}


Последнее обновление : 11 мая 2023 г.
Дата создания : 30 октября 2022 г.

Комментарии

Комментарии