How libexhq/libex works
1. What this service is
Libex is a Python API service that fronts Audible metadata. The core architecture is a FastAPI application that accepts book/author/series/narrator/search requests, fetches fresh data from Audible when needed, persists successful responses in PostgreSQL, and exposes a separate set of endpoints that query the local library only.
2. Primary request path
Most public endpoints follow the same flow: HTTP request → route layer with Pydantic schemas → service layer → cache/database lookup → Audible fetch if needed → normalize/enrich response → write to PostgreSQL → return response. That “fetch fresh, then persist” pattern is central to the design.
3. API boundary and routing
app/api/routes is organized by resource: books, authors, series, narrators, search, db, internal, and health/db utility routes. The route layer is the external contract and also handles compatibility details like region-prefixed search paths for Audiobookshelf and legacy endpoint aliases.
4. Audible integration boundary
app/services/audible contains the outbound integration with Audible. It is split by concern (client, books, authors, series, search) so the API layer does not talk to Audible directly. This is the main external dependency for live metadata, and it is the source of truth when data is requested.
5. Persistent data layer
app/db defines the relational model, async session management, and base metadata. PostgreSQL is the only backing datastore. The schema stores books, authors, series, narrators, genres, pivots/relationships, cache entries, and enrichment fields such as narrator profile metadata, plans, and virtual voice flags.
6. Read/write separation
app/services/db/reader.py and writer.py separate query logic from mutation logic. Readers power the /db/* endpoints and fallback lookup paths; writers persist freshly fetched Audible objects and related relationships. This boundary makes it easier to reason about “local library query” versus “ingest/update” behavior.
7. Cache subsystem
app/services/cache/manager.py implements an application-level cache backed by PostgreSQL, not Redis. Cache behavior is configurable via TTL and enable/disable flags. It sits between request handling and external fetches to reduce repeated Audible calls, but the local database remains the durable record even after cache expiry.
8. Background ingestion / seeding
app/services/seeder.py supports a background expansion process that walks relationships and discovers additional content over time. It is controlled by environment flags and intervals, and it uses the same Audible and database services as the request path. The internal API route likely provides a protected way to trigger or manage this behavior.
9. Cross-cutting concerns
app/core contains configuration, middleware, logging, exception handling, and shared utilities. These modules define the operational envelope around the API: environment-driven config, request/response middleware, structured logging, and consistent API error mapping.
10. Schema evolution and deployments
The repository is migration-driven with Alembic under migrations/, indicating a stable relational schema that evolves over time. The Dockerfile, docker-compose.yml, and GitHub Actions workflows show that the service is meant to run as a containerized API with PostgreSQL, with CI covering tests and publication.
11. Data enrichment
Narrator records are not just mirrored from Audible; they are augmented with external profile data from NarratorList/AussieNarrator when available. That enrichment is persisted and then exposed through the DB/narrator endpoints, adding a secondary metadata source to the main Audible pipeline.
12. Testing boundaries
The tests/ tree mirrors the main subsystems: API routes, services, cache behavior, DB reader/writer, exceptions, and health checks. That structure reflects the architecture: contract tests at the HTTP layer, unit tests around service orchestration, and lower-level tests for persistence and utilities.
Main entry points: main.py App entry · writer.py DB writer · router.py Books API · client.py Audible client
Components 32
API layer
FastAPI routes and request schemas
- App entry · Application bootstrap and route wiring
app/main.py - Books API · Book request endpoints and compatibility flow
app/api/routes/books/router.py - Book schema · Request and response models for books
app/api/routes/books/schemas.py - Authors API · Author request endpoints
app/api/routes/authors/router.py - Author schema · Request and response models for authors
app/api/routes/authors/schemas.py - Series API · Series request endpoints
app/api/routes/series/router.py - Series schema · Request and response models for series
app/api/routes/series/schemas.py - Narrators API · Narrator request endpoints
app/api/routes/narrators/router.py - Narrator schema · Request and response models for narrators
app/api/routes/narrators/schemas.py - Search API · Search endpoints including region-prefixed paths
app/api/routes/search/router.py - Search schema · Request and response models for search
app/api/routes/search/schemas.py - DB API · Local-library query endpoints
app/api/routes/db/router.py - Internal API · Protected operational and ingestion endpoints
app/api/routes/internal/router.py
Services
External integration, cache, persistence orchestration, and ingestion
- Audible client · Outbound Audible API access
app/services/audible/client.py - Books fetch · Book-specific Audible retrieval and normalization
app/services/audible/books.py - Authors fetch · Author-specific Audible retrieval and normalization
app/services/audible/authors.py - Series fetch · Series-specific Audible retrieval and normalization
app/services/audible/series.py - Search fetch · Audible search and lookup support
app/services/audible/search.py - Cache manager · Application cache backed by PostgreSQL
app/services/cache/manager.py - DB reader · Read paths for local-library and fallback lookups
app/services/db/reader.py - DB writer · Persistence for freshly fetched Audible objects and relationships
app/services/db/writer.py - Seeder · Relationship-walking expansion and background seeding
app/services/seeder.py
Data layer
PostgreSQL models, session management, and migrations
- Models · Relational entities for books, authors, series, narrators, genres, pivots, and cache
app/db/models.py - Session · Async session and connection management
app/db/session.py - Base · Shared SQLAlchemy metadata/base definitions
app/db/base.py - Migrations · Schema evolution history
migrations/env.py
Core
Configuration, middleware, logging, and shared utilities
- Config · Environment-driven application settings
app/core/config.py - Middleware · Request/response interception and cross-cutting HTTP behavior
app/core/middleware.py - Exceptions · Consistent API error handling
app/core/exceptions.py
Ops
Containerization and deployment support
- Dockerfile · Container image definition
Dockerfile - Compose · Local service composition with PostgreSQL
docker-compose.yml - CI workflows · Tests, publish, and cleanup automation
.github/workflows/tests.yml
Connections 46
- App entry → Books API: mounts · Registers book endpoints
- App entry → Authors API: mounts · Registers author endpoints
- App entry → Series API: mounts · Registers series endpoints
- App entry → Narrators API: mounts · Registers narrator endpoints
- App entry → Search API: mounts · Registers search endpoints
- App entry → DB API: mounts · Registers local DB endpoints
- App entry → Internal API: mounts · Registers internal endpoints
- App entry → Config: uses · Loads runtime configuration
- App entry → Middleware: wraps · Adds HTTP middleware
- App entry → Exceptions: maps · Installs API error handling
- Books API → Book schema: validates · Uses request/response models
- Books API → Cache manager: checks · Looks up cached responses first
- Books API → Books fetch: fetches · Requests fresh Audible book data
- Books API → DB writer: persists · Stores freshly fetched book data
- Authors API → Author schema: validates · Uses request/response models
- Authors API → Authors fetch: fetches · Requests fresh Audible author data
- Authors API → DB writer: persists · Stores fetched author data
- Series API → Series schema: validates · Uses request/response models
- Series API → Series fetch: fetches · Requests fresh Audible series data
- Series API → DB writer: persists · Stores fetched series data
- Narrators API → Narrator schema: validates · Uses request/response models
- Narrators API → DB reader: reads · Serves local narrator data and enrichment
- Search API → Search schema: validates · Uses request/response models
- Search API → Cache manager: checks · Uses cache to reduce repeated searches
- Search API → Search fetch: fetches · Performs Audible search lookups
- DB API → DB reader: reads · Queries local library only
- Internal API → Seeder: controls · Triggers or manages background expansion
- Cache manager → Session: uses · Stores cache entries in PostgreSQL
- Cache manager → Models: reads/writes · Operates on cache records
- DB reader → Session: queries · Executes read-only database access
- DB writer → Session: mutates · Executes database writes
- DB writer → Models: maps · Persists ORM entities and pivots
- Audible client → Config: configures · Uses credentials and runtime settings
- Books fetch → Audible client: calls · Uses shared Audible transport
- Authors fetch → Audible client: calls · Uses shared Audible transport
- Series fetch → Audible client: calls · Uses shared Audible transport
- Search fetch → Audible client: calls · Uses shared Audible transport
- Seeder → Books fetch: discovers · Walks relationships by fetching more content
- Seeder → DB reader: reads · Uses local graph and existing records
- Seeder → DB writer: persists · Writes newly discovered data
- Models → Base: extends · Built on shared ORM base metadata
- Session → Base: binds · Connects metadata to engine/session
- Migrations → Models: evolves · Tracks schema changes for the ORM model set
- Compose → Session: provisions · Provides PostgreSQL backing service in dev
- Dockerfile → App entry: packages · Builds the API service container
- CI workflows → Dockerfile: verifies · CI covers build and test automation