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}.");
}
}
}