Cayaqui.ApiClient
0.4.21
dotnet add package Cayaqui.ApiClient --version 0.4.21
NuGet\Install-Package Cayaqui.ApiClient -Version 0.4.21
<PackageReference Include="Cayaqui.ApiClient" Version="0.4.21" />
<PackageVersion Include="Cayaqui.ApiClient" Version="0.4.21" />
<PackageReference Include="Cayaqui.ApiClient" />
paket add Cayaqui.ApiClient --version 0.4.21
#r "nuget: Cayaqui.ApiClient, 0.4.21"
#:package Cayaqui.ApiClient@0.4.21
#addin nuget:?package=Cayaqui.ApiClient&version=0.4.21
#tool nuget:?package=Cayaqui.ApiClient&version=0.4.21
Cayaqui.ApiClient
Cliente HTTP tipado y Result-based para consumir APIs Cayaqui desde Blazor / MAUI / cualquier .NET.
Espeja el contrato de errores del companion server: el API serializa DomainError→ProblemDetails;
este paquete deserializa ProblemDetails→Result<T>.Failure(DomainError). Nunca lanza por error
de negocio — todo 4xx/5xx con ProblemDetails se mapea a Result<T> Failure.
Distribución propietaria — requiere contrato comercial con Cayaqui. Ver
LICENSE.txt.
Instalación
<PackageReference Include="Cayaqui.ApiClient" Version="0.2.0" />
Depende de Cayaqui.BuildingBlocks ≥ 0.4.0 (Result<T>, DomainError, ErrorType, Unit).
Sin dependencia ASP.NET (cliente puro).
Servicio tipado
Todos los servicios API implementan el marker IBaseApiService (regla global Cayaqui) y heredan
de BaseApiService, que expone verb-helpers que devuelven Result<T>:
using Cayaqui.ApiClient;
using Cayaqui.BuildingBlocks.Application; // Result<T>, Unit
public interface INotificationsApiService : IBaseApiService
{
Task<Result<PagedResult<NotificationDto>>> GetMineAsync(bool unreadOnly, int page, int pageSize, CancellationToken ct);
Task<Result<Unit>> MarkAsReadAsync(MarkAsReadRequest req, CancellationToken ct);
}
internal sealed class NotificationsApiService(HttpClient http)
: BaseApiService(http), INotificationsApiService
{
public Task<Result<PagedResult<NotificationDto>>> GetMineAsync(bool unreadOnly, int page, int pageSize, CancellationToken ct) =>
GetAsync<PagedResult<NotificationDto>>($"api/notifications?unreadOnly={unreadOnly}&page={page}&pageSize={pageSize}", ct);
public Task<Result<Unit>> MarkAsReadAsync(MarkAsReadRequest req, CancellationToken ct) =>
PostAsync("api/notifications/mark-as-read", req, ct); // → Result<Unit>
}
Verb-helpers (protected en BaseApiService)
| Helper | Devuelve |
|---|---|
GetAsync<T>(uri, ct) |
Result<T> |
PostAsync<TReq,T>(uri, body, ct) / PostAsync<TReq>(uri, body, ct) |
Result<T> / Result<Unit> |
PutAsync<TReq,T>(uri, body, ct) / PutAsync<TReq>(uri, body, ct) |
Result<T> / Result<Unit> |
DeleteAsync(uri, ct) / DeleteAsync<T>(uri, ct) |
Result<Unit> / Result<T> |
Comportamiento del núcleo:
- 2xx con body →
Result.Success. Body JSON inválido onull→Failure(Unexpected)(deserialization_error/empty_response). - 204 / vacío en overload
Unit→Success(Unit.Value). - 4xx/5xx → deserializa ProblemDetails →
Result.Failure(DomainError)(Type/Code/Message/Metadatarecuperados). - Transporte / timeout →
Failure(Unexpected, "transport_error"). La cancelación real delCancellationTokendel llamador sí propaga. - JSON: default web (camelCase, case-insensitive) + enums como string. Deben coincidir con las options del API. Overridable por ctor.
Consumo del resultado
var result = await notifications.GetMineAsync(unreadOnly: true, 1, 20, ct);
if (result.IsSuccess)
Render(result.Value);
else
ShowError(result.Error.Message); // result.Error : DomainError (Code, Message, Type, Metadata)
Autenticación
El paquete provee IAccessTokenProvider (lo implementa la app) + BearerTokenHandler:
services.AddCayaquiApiClientCore(); // registra BearerTokenHandler
services.AddCayaquiAccessTokenProvider<OboAccessTokenProvider>();// tu impl
services.AddHttpClient<INotificationsApiService, NotificationsApiService>(c => c.BaseAddress = apiBaseUrl)
.AddHttpMessageHandler<BearerTokenHandler>()
.AddStandardResilienceHandler(); // Polly — decisión tuya, no del paquete
Aspire / service discovery
El cliente es scheme-agnóstico (usa URIs relativas contra tu HttpClient), así que funciona con
service discovery sin wrapper — seteá la BaseAddress al nombre del recurso y agregá .AddServiceDiscovery():
builder.Services.AddServiceDiscovery();
builder.Services.AddCayaquiApiClientCore();
builder.Services.AddCayaquiAccessTokenProvider<TokenProvider>();
builder.Services.AddHttpClient<INotificationsApiService, NotificationsApiService>(
c => c.BaseAddress = new("https+http://daica-api")) // service discovery, no URL hardcodeada
.AddHttpMessageHandler<BearerTokenHandler>()
.AddServiceDiscovery();
⚠ Contrato del provider.
IHttpClientFactorypoolea los handlers (~2 min), así que la instancia deIAccessTokenProviderse reusa entre requests/usuarios. Tu impl debe leer el usuario actual en cadaGetAccessTokenAsync(fuente context-dynamic), no cachear en campos.
- API/MVC/Razor Pages:
ITokenAcquisition.GetAccessTokenForUserAsyncfunciona —IHttpContextAccessores AsyncLocal.- MAUI: MSAL
AcquireTokenSilent/Interactive(PublicClientApplicationsingleton).- 🔴 Blazor Server (InteractiveServer): las llamadas desde componentes interactivos corren en el circuit sin
HttpContext→ OBO víaITokenAcquisitionfalla, y el handler pooleado no ve el circuit. Obtené el token por un mecanismo circuit-safe: adquirirlo en el servicio tipado (circuit scope) y attachearlo per-call, un provider sobreAuthenticationStateProvider+ token store server-side, oMicrosoft.Identity.Web.IDownstreamApi.
Contrato de errores (round-trip)
Simétrico a Cayaqui.BuildingBlocks.AspNetCore.ProblemDetailsMapper (garantizado por test):
DomainError |
ProblemDetails |
|---|---|
Type (ErrorType) |
Title (= Type.ToString()); fallback por status code |
Code |
Extensions["code"]; fallback http_{status} |
Message |
Detail; fallback Title / reason phrase |
Metadata |
Extensions["errors"] |
ErrorType: Validation(400) · Unauthorized(401) · Forbidden(403) · NotFound(404) ·
Conflict/Concurrency(409) · Unexpected(500).
Versiones
v0.1.0 — Release inicial
Marker IBaseApiService, BaseApiService (verb-helpers Result-based, nunca lanza), mapeo inverso
ProblemDetails→Result<DomainError>, IAccessTokenProvider + BearerTokenHandler, DI mínimo
(AddCayaquiApiClientCore, AddCayaquiAccessTokenProvider<T>). Depende de Cayaqui.BuildingBlocks 0.4.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cayaqui.BuildingBlocks (>= 0.4.21)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Http (>= 10.0.9)
- Microsoft.Extensions.Logging (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.4.21 | 102 | 6/23/2026 |
| 0.4.20 | 102 | 6/23/2026 |
| 0.4.15 | 100 | 6/22/2026 |
| 0.4.14 | 100 | 6/22/2026 |
| 0.4.13 | 99 | 6/22/2026 |
| 0.4.10 | 112 | 6/20/2026 |
| 0.4.5 | 98 | 6/20/2026 |
| 0.4.3 | 95 | 6/20/2026 |
| 0.4.2 | 101 | 6/20/2026 |
| 0.4.1 | 98 | 6/20/2026 |
| 0.3.9 | 99 | 6/19/2026 |
| 0.3.8 | 98 | 6/18/2026 |
| 0.3.7 | 109 | 6/18/2026 |
| 0.3.6 | 98 | 6/18/2026 |
| 0.3.5 | 96 | 6/18/2026 |
| 0.3.4 | 97 | 6/17/2026 |
| 0.1.2 | 105 | 6/16/2026 |
| 0.1.1 | 105 | 6/16/2026 |
| 0.1.0 | 103 | 6/15/2026 |
0.1.0 — Release inicial. Cliente HTTP tipado Result-based: marker `IBaseApiService` + `BaseApiService` (verb-helpers Get/Post/Put/Delete → `Result<T>`, nunca lanza por error de negocio), mapeo inverso ProblemDetails→`Result<DomainError>` simétrico a `Cayaqui.BuildingBlocks.AspNetCore.ProblemDetailsMapper`, `IAccessTokenProvider` + `BearerTokenHandler` para auth reutilizable (Web OBO / MAUI MSAL), DI mínimo (`AddMpsApiClientCore`, `AddMpsAccessTokenProvider`). Sin dependencia ASP.NET. Depende de Cayaqui.BuildingBlocks 0.4.0.