Cayaqui.MPS.ApiClient
0.1.0
dotnet add package Cayaqui.MPS.ApiClient --version 0.1.0
NuGet\Install-Package Cayaqui.MPS.ApiClient -Version 0.1.0
<PackageReference Include="Cayaqui.MPS.ApiClient" Version="0.1.0" />
<PackageVersion Include="Cayaqui.MPS.ApiClient" Version="0.1.0" />
<PackageReference Include="Cayaqui.MPS.ApiClient" />
paket add Cayaqui.MPS.ApiClient --version 0.1.0
#r "nuget: Cayaqui.MPS.ApiClient, 0.1.0"
#:package Cayaqui.MPS.ApiClient@0.1.0
#addin nuget:?package=Cayaqui.MPS.ApiClient&version=0.1.0
#tool nuget:?package=Cayaqui.MPS.ApiClient&version=0.1.0
Cayaqui.MPS.ApiClient
Cliente HTTP tipado y Result-based para consumir APIs MPS 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.MPS.ApiClient" Version="0.1.0" />
Depende de Cayaqui.MPS.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 MPS.ApiClient;
using MPS.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.AddMpsApiClientCore(); // registra BearerTokenHandler
services.AddMpsAccessTokenProvider<OboAccessTokenProvider>();// tu impl
services.AddHttpClient<INotificationsApiService, NotificationsApiService>(c => c.BaseAddress = apiBaseUrl)
.AddHttpMessageHandler<BearerTokenHandler>()
.AddStandardResilienceHandler(); // Polly — decisión tuya, no del paquete
⚠ 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 MPS.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
(AddMpsApiClientCore, AddMpsAccessTokenProvider<T>). Depende de Cayaqui.MPS.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.MPS.BuildingBlocks (>= 0.4.0)
- Microsoft.Extensions.Http (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
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.1.0 | 99 | 6/4/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 `MPS.BuildingBlocks.AspNetCore.ProblemDetailsMapper`, `IAccessTokenProvider` + `BearerTokenHandler` para auth reutilizable (Web OBO / MAUI MSAL), DI mínimo (`AddMpsApiClientCore`, `AddMpsAccessTokenProvider`). Sin dependencia ASP.NET. Depende de Cayaqui.MPS.BuildingBlocks 0.4.0.