using System.Net.Http.Json; using System.Text.Json.Serialization; using Big.Application; namespace Big.Infrastructure; /// /// HTTP client to the ACL service — the boundary the domain crosses to open a zaak (§8.1). It POSTs /// the bsn to the ACL's /zaken endpoint and returns the created zaak URL; it never constructs /// ZGW URLs or talks to OpenZaak itself. /// public sealed class AclHttpClient(HttpClient http, AclOptions options) : IAclClient { public async Task OpenZaakAsync(string bsn, string reference, CancellationToken ct = default) { using var response = await http.PostAsJsonAsync( new Uri(options.BaseUrl, "zaken"), new OpenZaakRequest(bsn, reference), ct); response.EnsureSuccessStatusCode(); var opened = await response.Content.ReadFromJsonAsync(ct) ?? throw new InvalidOperationException("The ACL returned an empty zaak response."); return new Uri(opened.ZaakUrl); } public async Task ApproveZaakAsync(Uri zaakUrl, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); using var response = await http.PostAsJsonAsync( new Uri(options.BaseUrl, "statussen"), new SetStatusRequest(zaakUrl.ToString()), ct); response.EnsureSuccessStatusCode(); } public async Task CancelZaakAsync(Uri zaakUrl, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); using var response = await http.PostAsJsonAsync( new Uri(options.BaseUrl, "annuleringen"), new CancelZaakRequest(zaakUrl.ToString()), ct); response.EnsureSuccessStatusCode(); } public async Task StoreDiplomaAsync(Uri zaakUrl, byte[] content, string fileName, string contentType, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); ArgumentNullException.ThrowIfNull(content); // The file crosses this boundary base64-encoded in JSON — the domain and ACL contracts are // JSON, and a diploma is small (S-10b, ADR). The ACL turns it into a ZGW informatieobject. using var response = await http.PostAsJsonAsync( new Uri(options.BaseUrl, "documenten"), new StoreDocumentRequest(zaakUrl.ToString(), Convert.ToBase64String(content), fileName, contentType), ct); response.EnsureSuccessStatusCode(); var stored = await response.Content.ReadFromJsonAsync(ct) ?? throw new InvalidOperationException("The ACL returned an empty document response."); return new Uri(stored.InformatieobjectUrl); } private sealed record OpenZaakRequest( [property: JsonPropertyName("bsn")] string Bsn, [property: JsonPropertyName("reference")] string Reference); private sealed record OpenZaakResponse([property: JsonPropertyName("zaakUrl")] string ZaakUrl); private sealed record SetStatusRequest([property: JsonPropertyName("zaakUrl")] string ZaakUrl); private sealed record CancelZaakRequest([property: JsonPropertyName("zaakUrl")] string ZaakUrl); private sealed record StoreDocumentRequest( [property: JsonPropertyName("zaakUrl")] string ZaakUrl, [property: JsonPropertyName("contentBase64")] string ContentBase64, [property: JsonPropertyName("fileName")] string FileName, [property: JsonPropertyName("contentType")] string ContentType); private sealed record StoreDocumentResponse( [property: JsonPropertyName("informatieobjectUrl")] string InformatieobjectUrl); }