using MaBibli.Shared.Dtos; namespace MaBibli.Api.Services.Isbn; public interface IBnfClient { /// /// Interroge le SRU de la BnF pour une forme d'ISBN donnée. /// Renvoie une liste vide si la BnF ne connaît pas l'ISBN ou si elle est injoignable ; /// dans ce second cas explique pourquoi. /// Task<(IReadOnlyList Candidats, string? Avertissement)> RechercherAsync( string isbn, string? urlCouverture, CancellationToken ct = default); } /// /// Client de l'API SRU du catalogue général de la BnF (gratuite, sans clé). /// public sealed class BnfClient(HttpClient http, ILogger logger) : IBnfClient { /// Nom du client typé enregistré dans IHttpClientFactory. public const string NomHttpClient = "bnf"; public const string UrlBase = "https://catalogue.bnf.fr/"; public async Task<(IReadOnlyList Candidats, string? Avertissement)> RechercherAsync( string isbn, string? urlCouverture, CancellationToken ct = default) { // recordSchema=dublincore et non MARC : dc:title / dc:creator / dc:publisher se mappent // directement, là où l'UNIMARC demanderait un décodage complet. var url = "api/SRU" + "?version=1.2" + "&operation=searchRetrieve" + $"&query={Uri.EscapeDataString($"bib.isbn all \"{isbn}\"")}" + "&recordSchema=dublincore" + "&maximumRecords=5"; try { using var reponse = await http.GetAsync(url, ct); if (!reponse.IsSuccessStatusCode) { logger.LogWarning("BnF a répondu {Code} pour l'ISBN {Isbn}", (int)reponse.StatusCode, isbn); return ([], $"La BnF a répondu {(int)reponse.StatusCode} pour {isbn}."); } var xml = await reponse.Content.ReadAsStringAsync(ct); return (BnfSruParser.Parser(xml, isbn, urlCouverture), null); } catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException) { // Une source indisponible ne doit pas faire échouer la cascade : on bascule sur la suivante. logger.LogWarning(ex, "BnF injoignable pour l'ISBN {Isbn}", isbn); return ([], $"BnF injoignable ({ex.GetType().Name}) pour {isbn}."); } catch (System.Xml.XmlException ex) { logger.LogWarning(ex, "Réponse BnF illisible pour l'ISBN {Isbn}", isbn); return ([], $"Réponse BnF illisible pour {isbn}."); } } }