Phase 2 : service de lookup ISBN en cascade BnF puis OpenLibrary

Recuperation des metadonnees d'un livre a partir de son ISBN, cote serveur
uniquement (aucune interface, aucune persistance).

Cascade : BnF en ISBN-13, puis BnF en ISBN-10 converti, puis OpenLibrary.
La conversion 13 -> 10 est indispensable et non optionnelle : la BnF indexe
l'ISBN tel qu'imprime, les ouvrages d'avant 2007 ne portent qu'un ISBN-10 et
sont introuvables par l'EAN-13 que lit le scanner.

Toutes les notices trouvees sont remontees (jusqu'a 5) : un meme ISBN peut
correspondre a plusieurs reeditions, le choix revient a l'utilisateur.

Le double appel /isbn puis /authors d'OpenLibrary est bien fait, avec repli
sur l'oeuvre quand l'edition ne porte aucun auteur : c'est le bug de BookLogr
(titre rempli, auteur vide) qu'il ne faut pas reproduire.

La couverture vient toujours d'OpenLibrary, avec ?default=false pour obtenir
un 404 plutot qu'une image placeholder.

87 tests xUnit, sur fixtures enregistrees : aucune dependance au reseau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-17 22:22:47 +02:00
co-authored by Claude Opus 5
parent 4990e41f3e
commit f8f30dbcf7
37 changed files with 1661 additions and 0 deletions
+24
View File
@@ -1,4 +1,6 @@
using MaBibli.Api.Data;
using MaBibli.Api.Endpoints;
using MaBibli.Api.Services.Isbn;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
@@ -8,6 +10,26 @@ builder.Services.AddOpenApi();
builder.Services.AddDbContext<MaBibliDbContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("MaBibli")));
// Lookup ISBN : clients typés via IHttpClientFactory (pas de HttpClient instancié à la main).
// Timeout court : une source lente ne doit pas bloquer la cascade, l'appelant bascule sur la suivante.
var timeoutSources = TimeSpan.FromSeconds(10);
builder.Services.AddHttpClient<IBnfClient, BnfClient>(http =>
{
http.BaseAddress = new Uri(BnfClient.UrlBase);
http.Timeout = timeoutSources;
http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)");
});
builder.Services.AddHttpClient<IOpenLibraryClient, OpenLibraryClient>(http =>
{
http.BaseAddress = new Uri(OpenLibraryClient.UrlBase);
http.Timeout = timeoutSources;
http.DefaultRequestHeaders.UserAgent.ParseAdd("MaBibli/0.1 (bibliotheque personnelle auto-hebergee)");
});
builder.Services.AddScoped<IIsbnLookupService, IsbnLookupService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
@@ -20,6 +42,8 @@ if (app.Environment.IsDevelopment())
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.MapIsbnEndpoints();
app.MapFallbackToFile("index.html");
app.Run();