A RESTful API for managing books with automatic data enrichment via the Open Library API. Built with Django, PostgreSQL, and Redis — following clean architecture with domain-driven design.
- CRUD operations for books with filtering, search, and pagination
- ISBN-based data enrichment — automatically fetches title, authors, publishers, page count, and description from the Open Library API
- Redis caching — decorator-based cache layer with 2-hour TTL to minimize external API calls
- Production-ready Docker — multi-stage builds, separate dev/prod configs, health checks via dockerize
- CI/CD — GitHub Actions pipeline with full integration tests
| Layer | Technology |
|---|---|
| Framework | Django 5, Django REST Framework |
| Database | PostgreSQL 13 |
| Cache | Redis 5 |
| Testing | Pytest (22 test files) |
| CI/CD | GitHub Actions |
| Containerization | Docker, Docker Compose |
The project follows clean architecture with dependency inversion:
┌─────────────────────────────────────────┐
│ API Views (REST endpoints) │
│ Filters, Pagination │
└────────────────┬────────────────────────┘
│
┌────────────────▼────────────────────────┐
│ Application Services │
│ BookService (enrichment orchestration) │
└────────────────┬────────────────────────┘
│
┌────────────────▼────────────────────────┐
│ Domain Layer │
│ Book Entity, Value Objects (ISBN10, │
│ ISBN13, PublishDate), Factory, │
│ Repository Interface │
└────────────────┬────────────────────────┘
│
┌────────────────▼────────────────────────┐
│ Infrastructure │
│ DjangoBookRepository, Redis Cache, │
│ OpenLibraryClient │
└─────────────────────────────────────────┘
books/
├── domain/ # Business logic (no framework dependencies)
│ ├── entity/ # Book entity with behavior
│ ├── value_object/ # ISBN10, ISBN13, PublishDate (validated, immutable)
│ ├── repository/ # Abstract repository interface
│ └── factory/ # Entity construction
├── application/
│ ├── api/ # REST views + tests
│ └── service/ # Enrichment service
└── infrastructure/
├── models/ # Django ORM + model mapper
├── repository/ # Repository implementation
├── cache/ # Redis cache decorator
└── open_library/ # External API client
| Pattern | Where | Why |
|---|---|---|
| Repository | domain/repository/ → infrastructure/repository/ |
Abstracts persistence; domain doesn't know about Django ORM |
| Value Objects | domain/value_object/ |
ISBN10 validates length=10, PublishDate prevents future dates — invalid states are unrepresentable |
| Factory | domain/factory/ |
Centralizes entity construction with UUID generation and value object creation |
| Decorator | infrastructure/cache/ |
@redis_cache(prefix, ttl) — transparent caching on any method |
| Service Layer | application/service/ |
Orchestrates the two-step enrichment flow (book info → work description) |
Book Create/Update
│
├─ Has ISBN? ──No──→ Skip enrichment
│
└─ Yes
│
├─ 1. Fetch book info (title, authors, publishers, pages, publish date)
│ GET /api/volumes/brief/isbn/{isbn}.json [cached 2h]
│
└─ 2. Fetch description via work key
GET /{workKey}.json [cached 2h]
│
└─→ Merge enriched data into Book entity
Each step is independently cached and fails gracefully — partial enrichment is returned if the description call fails.
make up # Start Django + PostgreSQL + Redis
make seed-db # Seed database with sample books
# API available at http://localhost:8000make up-prod # Multi-stage Docker build, optimized image, no volume mountsA Postman collection is included with all endpoints.
Endpoints:
GET /books/— List books (supports filtering by title, ISBN, author, publisher + pagination)GET /books/{id}/— Get book detailsPOST /books/— Create book (triggers enrichment if ISBN provided)PUT /books/{id}/— Update bookDELETE /books/{id}/— Delete book
22 test files covering domain, service, API, repository, and cache layers:
make test- Domain tests — entity validation, value object constraints
- Service tests — enrichment workflow with mocked external API
- API tests — CRUD operations, filtering, pagination
- Repository tests — query building, model mapping
- Cache tests — Redis integration, TTL behavior
| Command | Description |
|---|---|
make up |
Start development environment |
make up-prod |
Start production environment |
make test |
Run all tests |
make migrate |
Run Django migrations |
make format |
Format code with black |
make logs |
Show all service logs |
make shell-web |
Django container shell |
make shell-db |
PostgreSQL container shell |
make down |
Stop all services |
make clean |
Stop services + remove volumes |