HTTP Client
HTTP Client⌗
ArturRios.Util.WebApi gives you a thin base for typed clients that call another web API:
BaseWebApiClient owns a shared HttpGateway, and BaseWebApiClientRoute groups related endpoints
under a base URL with helpers for authenticating and carrying the resulting bearer token.
BaseWebApiClient⌗
BaseWebApiClient is abstract and exposes a protected HttpGateway Gateway that every route object uses
to issue requests. It has two constructors:
BaseWebApiClient(HttpClient httpClient)— wraps an existingHttpClient. Prefer this one: it lets the client be created throughIHttpClientFactory(viaAddHttpClient<T>()), which manages the underlyingHttpClient’s lifetime and connection pooling for you and is what lets you attach message handlers likeTracePropagationHandler.BaseWebApiClient(string baseUrl)— constructs its ownHttpClientwithBaseAddress = baseUrl. Simpler for quick/manual use, but you loseIHttpClientFactory’s pooling and the ability to attach handlers through DI.
Both constructors call the abstract SetRoutes() method before returning, so a derived class implements
it to instantiate its route objects against the shared Gateway:
public class MyApiClient : BaseWebApiClient
{
public AccountsRoute Accounts { get; private set; } = null!;
public MyApiClient(HttpClient httpClient) : base(httpClient) { }
protected override void SetRoutes()
{
Accounts = new AccountsRoute(Gateway);
}
}
BaseWebApiClientRoute⌗
BaseWebApiClientRoute(HttpGateway gateway) is the base for a group of related routes on the remote API.
It exposes:
abstract string BaseUrl— the base path this route group is mounted under (e.g./accounts).AuthenticateAsync(Credentials credentials, string authRoute)— postscredentialstoauthRoutevia the sharedGatewayand returns the resultingAuthentication. ThrowsWebApiClientExceptionif the response comes back with no body.Authorize(string authToken)— setsGateway.Client.DefaultRequestHeaders.Authorizationto aBearerheader carryingauthToken. This is a plain assignment, so it’s idempotent — calling it again (e.g. after re-authenticating) simply replaces the previous header rather than accumulating anything.AuthenticateAndAuthorizeAsync(Credentials credentials, string authRoute)— callsAuthenticateAsyncthenAuthorizewith the returned token, in one call.
public class AccountsRoute(HttpGateway gateway) : BaseWebApiClientRoute(gateway)
{
public override string BaseUrl => "/accounts";
public Task LoginAsync(Credentials credentials) =>
AuthenticateAndAuthorizeAsync(credentials, $"{BaseUrl}/login");
}
After LoginAsync completes, every subsequent call made through the shared Gateway — from Accounts
or any other route object on the same client — carries the Authorization: Bearer header, since they all
share the same underlying HttpClient.
WebApiClientException⌗
A plain Exception subclass raised when a BaseWebApiClientRoute operation can’t complete — currently,
only when AuthenticateAsync gets a response with no body. Catch it around login calls if you want to
distinguish “the remote API is unreachable/malformed” from a normal authentication failure surfaced
through the Authentication.Valid flag.
Pairing with TracePropagationHandler⌗
Because the HttpClient-based constructor is built for IHttpClientFactory, you can attach
TracePropagationHandler (see Middleware & Diagnostics) so every
outgoing call from the client carries the current request’s W3C trace id:
builder.Services.AddTransient<TracePropagationHandler>();
builder.Services.AddHttpClient<MyApiClient>()
.AddHttpMessageHandler<TracePropagationHandler>();
flowchart LR
Ctor["MyApiClient(HttpClient)"] --> SetRoutes["SetRoutes()"]
SetRoutes --> Accounts["AccountsRoute(Gateway)"]
Accounts -- "AuthenticateAndAuthorizeAsync" --> Login["POST /accounts/login"]
Login -- "Authentication.Token" --> Authorize["Authorize(token)"]
Authorize --> Header["Gateway.Client default Authorization header"]
Header --> Calls["Subsequent calls via Gateway"]
Calls -- "TracePropagationHandler" --> Downstream["Downstream API"]
Where to next⌗
- Middleware & Diagnostics —
TracePropagationHandlerand the trace id it propagates. - Security —
Credentials,Authenticationand the login flow this client typically calls into. - Responses — the
ArturRios.Outputenvelopes returned by the APIs these clients call.