CQRS product catalog for books — ASP.NET Core 6 microservices with a live demo UI.
Demo: https://amulyavarshney.github.io/product-catalog/
| Piece | Role |
|---|---|
Demo UI (docs/) |
Browse, search, filter, sort, paginate, create, update, delete |
| BookCommand.Service | Write API + transactional outbox |
| BookQuery.Service | Read API + RabbitMQ consumer (idempotent soft-delete projection) |
| BookCatalog.Gateway | YARP reverse proxy (:8080) |
| BookCatalog.Contracts | Shared DTOs, events, exceptions |
| BookCatalog.Tests | Unit + API contract tests |
| docker-compose | SQL Server, RabbitMQ, both services, gateway |
Architecture:
Client / Demo UI
→ Gateway (:8080)
├─ /command/** → BookCommand (:5001) → BookCommand DB → Outbox → RabbitMQ
└─ /query/** → BookQuery (:5002) ← RabbitMQ → BookQuery DB
Open the GitHub Pages site, or open docs/index.html locally.
- Demo (local) — full CRUD in browser storage (works offline on Pages)
- Live API — talk to a running gateway (
http://localhost:8080by default)
Features mirrored from the API:
- List with
search,author,sortBy,sortDir,page,pageSize - Create / update (including title)
- Soft-delete semantics on the services; demo mode removes the row from local storage
docker compose up --build| Service | URL |
|---|---|
| Demo UI (Pages) | https://amulyavarshney.github.io/product-catalog/ |
| Gateway | http://localhost:8080 |
| Command API | http://localhost:5001 |
| Query API | http://localhost:5002 |
| RabbitMQ UI | http://localhost:15672 (guest / guest) |
Gateway examples:
curl -X POST http://localhost:8080/command/api/v1/book \
-H "Content-Type: application/json" \
-d '{"title":"Clean Code","description":"A handbook","author":"Robert C. Martin"}'
curl "http://localhost:8080/query/api/v1/book?page=1&pageSize=20&search=clean&sortBy=title"Health: GET /health on each service and the gateway.
- Start SQL Server and RabbitMQ.
- Set
ConnectionStrings:DefaultConnectionandRabbitMQConfigin each serviceappsettings.json. - Run:
dotnet run --project BookCommand.Service
dotnet run --project BookQuery.Service
dotnet run --project BookCatalog.GatewayEF migrations create schema on startup (and create the database if missing).
| Method | Path | Status |
|---|---|---|
| POST | /api/v1/book |
201 |
| PUT | /api/v1/book/{id} |
204 |
| DELETE | /api/v1/book/{id} |
204 |
| Method | Path | Status |
|---|---|---|
| GET | /api/v1/book |
200 (paged) |
| GET | /api/v1/book/{id} |
200 / 404 |
Swagger is enabled in Development at /swagger.
JWT is optional (Authentication:Enabled, default false). When enabled, a global authorize filter protects controllers.
| Key | Purpose |
|---|---|
ConnectionStrings:DefaultConnection |
SQL Server |
RabbitMQConfig:* |
Host, credentials, exchange, queue, routing key, DLQ |
Authentication:Enabled |
Toggle JWT |
dotnet test BookCatalog.TestsThis repo publishes the docs/ folder to GitHub Pages (project site path /product-catalog/).
See LICENSE.txt.