BookLibraryAPI is a modular, layered .NET 8 Web API for managing a library of books and users, following Clean Architecture and SOLID principles. It supports JWT authentication, role-based authorization, email notifications, and is ready for containerized development with Docker and Mailpit.
- Book Model
- Id (int), Title (string), Author (string), Year (int)
- Endpoints
POST /books
: Create a new book (Moderator or Admin only)GET /books
: List all books (all users)
- Validation
- All input is validated using FluentValidation.
- JWT Authentication & Roles
- JWT authentication with roles: Admin (all permissions), Moderator (create/update), User (read only)
- Endpoints are protected by role-based authorization.
- Welcome Email on Book Creation
- When a new book is created, management is notified by email (business rule).
- This is implemented in the Application Layer (CreateBookCommandHandler) and uses a local SMTP server (Mailpit or Papercut) for development/testing.
- CQRS with MediatR
- All commands and queries are handled via MediatR for clean separation of concerns.
- Error Handling Middleware
- Custom middleware returns errors as ProblemDetails for consistent API responses.
- PostgreSQL & EF Core
- PostgreSQL is used as the database, with EF Core for data access and migrations.
- Caching
-
Book list queries are cached for performance using a cache service (
ICacheService
). -
The cache is automatically invalidated after creating or updating a book to ensure fresh data.
-
-
Caching is implemented in the Application layer (handlers) and the actual cache provider is implemented in the Infrastructure layer.
-
Main files:
src/Application/BookLibraryAPI.Application/Common/Services/Caching/ICacheService.cs
(interface)src/Application/BookLibraryAPI.Application/Features/Books/Queries/GetAllBooks/GetAllBooksQueryHandler.cs
(cache usage)src/Application/BookLibraryAPI.Application/Features/Books/Commands/CreateBook/CreateBookCommandHandler.cs
(cache invalidation)src/Application/BookLibraryAPI.Application/Features/Books/Commands/UpdateBook/UpdateBookCommandHandler.cs
(cache invalidation)src/Infrastructure/BookLibraryAPI.Infrastructure/Services/Caching/
(implementation)
-
- Books CRUD: Create, read, update, and list books with validation and error handling.
- User Management: Register, login, and manage users with hashed passwords and roles (Admin, Moderator, User).
- Authentication & Authorization: JWT-based authentication, role-based endpoint protection.
- Email Notifications: Sends emails (e.g., on book creation) using MailKit and Mailpit for local development.
- Validation: Uses FluentValidation for DTO and command validation.
- CQRS & MediatR: Command and query separation with MediatR.
- SOLID Principles: Codebase is organized for maintainability and testability.
- Docker-Ready: Includes Docker Compose for API and Mailpit (SMTP testing).
- Swagger/OpenAPI: Interactive API documentation with JWT support.
src/Core/BookLibraryAPI.Core.Domain
: Domain entities, value objects, interfaces, and core logic.src/Application/BookLibraryAPI.Application
: Application layer with DTOs, commands, queries, validators, mappers, and MediatR handlers.src/Infrastructure/BookLibraryAPI.Infrastructure
: Data access, repositories, services (email, JWT), and settings.src/Presentation/BookLibraryAPI.Presentation
: API endpoints, middleware, DI, and startup configuration.
-
Start Mailpit (SMTP for dev):
docker compose up -d mailpit
Mailpit Web UI: http://localhost:8025
-
Configure Email (for local dev): In
appsettings.Development.json
:"Email": { "Host": "localhost", "Port": "3025", "From": "library@example.com", "To": "admin@example.com" }
(If running API in Docker, use
"Host": "mailpit", "Port": "1025"
) -
Run the API:
dotnet run --project src/Presentation/BookLibraryAPI.Presentation
-
Swagger UI: http://localhost:7000/swagger (or the port in your launch settings)
- Use
/api/auth/register
to create a user. - Use
/api/auth/login
to get a JWT token. - Use the "Authorize" button in Swagger UI to authenticate requests.
POST /api/auth/register
— Register a new userPOST /api/auth/login
— Login and receive a JWT token
GET /api/books
— Get all books (requires authentication)GET /api/books/{id}
— Get a book by ID (requires authentication)POST /api/books
— Create a new book (requires Moderator or Admin)PUT /api/books/{id}
— Update a book (requires Moderator or Admin)
BookLibraryAPI/
├── compose.yaml
├── README.md
├── src/
│ ├── Application/
│ │ └── BookLibraryAPI.Application/
│ │ ├── Common/
│ │ │ ├── DTOs/
│ │ │ │ ├── Books/
│ │ │ │ └── Users/
│ │ │ └── Mappers/
│ │ ├── Services/
│ │ │ ├── Authentication/
│ │
│ │ ├── Features/
│ │ │ ├── Books/
│ │ │ └── Users/
│ │ └── DependencyInjection.cs
│ ├── Core/
│ │ └── BookLibraryAPI.Core.Domain/
│ │ ├── Books/
│ │ ├── Users/
│ │ │ └── Enums/
│ │ ├── Common/
│ │ │ └── Exceptions/
│ │ ├── Interfaces/
│ │ │ ├── Ports/
│ │ │ └── Repositories/
│ │ └── ValueObjects/
│ ├── Infrastructure/
│ │ └── BookLibraryAPI.Infrastructure/
│ │ ├── Adapters/
│ │ │ └── Email/
└── Caching/
│ │ ├── Persistence/
│ │ │ ├── Configurations/
│ │ │ └── Migrations/
│ │ ├── Repositories/
│ │ ├── Services/
│ │ │ ├── Authentication/
│ │
│ │ └── Settings/
│ │ └── DependencyInjection.cs
│ └── Presentation/
│ └── BookLibraryAPI.Presentation/
│ ├── Endpoints/
│ ├── Extensions/
│ ├── Middleware/
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Program.cs
│ └── Dockerfile
services:
mailpit:
image: axllent/mailpit:latest
ports:
- "8025:8025"
- "3025:1025"
restart: unless-stopped
- When a new book is created, management must be notified by email.
- This is a business requirement, not just a technical improvement.
- The email notification logic is implemented in the Application Layer (specifically, in the CreateBookCommandHandler) and is triggered after a book is successfully added.
- This ensures the business rule is enforced as part of the use case logic.

This project follows the principles of Hexagonal Architecture (Ports and Adapters):
- Core Domain: Contains business entities, value objects, and domain logic. It is independent of any external frameworks or technologies.
- Application Layer: Contains use cases (commands, queries, handlers) and orchestrates business rules. It depends only on the core domain and defines ports (interfaces) for external interactions.
- Ports: Interfaces in the Core or Application layer that define contracts for external services (e.g., repositories, email notifications).
- Adapters: Infrastructure implementations of ports (e.g., EF Core repositories, email services). These are injected into the application via dependency injection.
- Presentation Layer: Minimal API endpoints, middleware, and configuration. This layer is responsible for HTTP, validation, and error handling, and delegates business logic to the Application layer.
This separation ensures:
-
Business logic is isolated and testable.
-
Infrastructure and frameworks can be swapped with minimal impact.
-
The system is maintainable, extensible, and follows Clean Architecture best practices.
- Add new features in the Application layer (commands, queries, handlers).
- Add new endpoints in the Presentation layer.
- Add new services (e.g., notifications) in the Infrastructure layer.
Pull requests are welcome! Please follow the existing code style and add tests for new features.
MIT
- The API now supports HTTPS in Docker using a development certificate.
- Default HTTPS port is
9443
(seecompose.yaml
andappsettings.json
). - Access the API in Docker at:
https://localhost:9443/swagger
- The
Email
section inappsettings.json
now includes a requiredTo
field to avoid null recipient errors. - SMTP configuration keys in code were fixed to match the settings (
SmtpHost
,SmtpPort
).
- The GitHub Actions workflow (
.github/workflows/ci-cd.yml
) now includes:- Build, test (unit & integration), and artifact upload.
- Docker image build and push to DockerHub.
- Docker Compose deployment.
- Mailpit service for email integration tests, ensuring all tests pass in CI.



- Run:
docker compose up -d or docker pull abdulwaisa/booklibraryapi
- Visit:
- API:
https://localhost:9443/swagger
- Mailpit UI:
http://localhost:8025
- API:
- Check logs:
docker compose logs app
- On every push/PR to
main
, the workflow will:- Build and test the app.
- Deploy the latest image with Docker Compose.
- You can view workflow status and logs in the GitHub Actions tab.

The project includes comprehensive unit and integration tests:
- Unit Tests: Located in
tests/BookLibraryAPI.UnitTests
. Run with:dotnet test tests/BookLibraryAPI.UnitTests/BookLibraryAPI.UnitTests.csproj
- Integration Tests: Located in
tests/BookLibraryAPI.IntegrationTests
. These use Testcontainers for PostgreSQL, Redis, and Mailpit. Run with:dotnet test tests/BookLibraryAPI.IntegrationTests/BookLibraryAPI.IntegrationTests.csproj
- CI/CD: All tests are automatically run in GitHub Actions on every push and pull request to
main
. Test results are uploaded as artifacts.
You can view test results in the GitHub Actions tab or by running the above commands locally.
You can use the following predefined users to log in during development/testing:
Role | Username | Password |
---|---|---|
Admin | admin |
admin123 |
Moderator | moderator |
mod123 |
User | user |
user123 |
🔐 Note: Passwords are hashed using BCrypt at runtime. The plain-text versions above are only for testing purposes.