Production-ready REST API for todo management built with .NET 8, Clean Architecture, Testcontainers, Docker, and comprehensive testing.
This project demonstrates production-ready practices beyond typical CRUD tutorials:
| Feature | Implementation |
|---|---|
| Real Database Testing | Integration tests run against actual PostgreSQL using Testcontainers β not in-memory fakes |
| Full HTTP Testing | Tests execute real HTTP requests through WebApplicationFactory |
| Rate Limiting | Custom token bucket algorithm with HTTP 429 responses and Retry-After headers |
| Resilient Patterns | Polly retry policies with exponential backoff |
| Clean Architecture | Strict 4-layer separation with dependency injection |
| CI/CD Pipeline | GitHub Actions with PostgreSQL service container |
| Security Scanning | Automated CodeQL analysis on every push |
| Code Coverage | Codecov integration with coverage reports |
- Full CRUD Operations β Create, Read, Update, Delete todos
- Advanced Queries β Search by ID/title, filter upcoming tasks (today/week/custom periods)
- Partial Updates β Update completion percentage or mark as done separately
- Pagination Support β Efficient handling of large datasets with metadata
- Rate Limiting β Token bucket algorithm protecting API from abuse
- Docker Ready β One-command deployment with Docker Compose
- Comprehensive Testing β Unit and integration tests with real PostgreSQL
- API Documentation β Interactive Swagger/OpenAPI 3.0 documentation
| Category | Technology |
|---|---|
| Framework | .NET 8, ASP.NET Core Web API |
| Database | PostgreSQL 15+ with Entity Framework Core 8 |
| Testing | xUnit, Testcontainers, Moq, WebApplicationFactory |
| Resilience | Polly (retry policies with exponential backoff) |
| Documentation | Swagger / OpenAPI 3.0 |
| Containerization | Docker, Docker Compose |
| CI/CD | GitHub Actions |
| Security | CodeQL Analysis |
| Coverage | Codecov |
This project follows Clean Architecture principles with strict layer separation:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API Layer β
β Controllers, Middleware, Swagger, DI β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Application Layer β
β Services, DTOs, Validation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Core Layer β
β Entities, Interfaces, Exceptions β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Infrastructure Layer β
β EF Core DbContext, Repositories, Migrations β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
src/
βββ TodoTaskAPI.API/ # Entry point, HTTP layer
β βββ Controllers/ # API endpoints
β βββ Middleware/ # Rate limiting, error handling, logging
β βββ Swagger/ # API documentation config
βββ TodoTaskAPI.Application/ # Business logic
β βββ DTOs/ # Data transfer objects
β βββ Interfaces/ # Service contracts
β βββ Services/ # Service implementations
βββ TodoTaskAPI.Core/ # Domain layer
β βββ Entities/ # Domain models
β βββ Exceptions/ # Custom exceptions
β βββ Interfaces/ # Repository contracts
βββ TodoTaskAPI.Infrastructure/ # Data access
βββ Data/ # DbContext, seed data
βββ Migrations/ # EF Core migrations
βββ Repositories/ # Repository implementations
tests/
βββ TodoTaskAPI.IntegrationTests/ # Full-stack tests with real PostgreSQL
β βββ Api/ # API-level tests
β βββ Database/ # Database consistency tests
β βββ Endpoints/ # CRUD endpoint tests
β βββ Health/ # Health check tests
β βββ Infrastructure/ # Testcontainers setup
β βββ Performance/ # Rate limiting tests
βββ TodoTaskAPI.UnitTests/ # Unit tests with mocks
βββ Controllers/
βββ DTOs/
βββ Middleware/
βββ Repositories/
βββ Services/
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/todos |
Get all todos (supports pagination) |
GET |
/api/todos/search |
Search todos by ID or title |
GET |
/api/todos/upcoming |
Get upcoming todos (today/tomorrow/week/custom) |
POST |
/api/todos |
Create a new todo |
PUT |
/api/todos/{id} |
Update existing todo |
DELETE |
/api/todos/{id} |
Delete todo |
PATCH |
/api/todos/{id}/completion |
Update completion percentage |
PATCH |
/api/todos/{id}/done |
Mark todo as done/undone |
# Get all todos with pagination
curl "http://localhost:5034/api/todos?pageNumber=1&pageSize=10"
# Get upcoming todos for today
curl "http://localhost:5034/api/todos/upcoming?period=Today"
# Create a new todo
curl -X POST "http://localhost:5034/api/todos" \
-H "Content-Type: application/json" \
-d '{"title":"Complete project","expiryDateTime":"2025-12-31T23:59:59Z"}'
# Update completion percentage
curl -X PATCH "http://localhost:5034/api/todos/{id}/completion" \
-H "Content-Type: application/json" \
-d '{"percentComplete": 75}'# Clone the repository
git clone https://github.com/JakubPatkowski/TodoTaskApi
cd TodoTaskApi
# Build and run with Docker Compose
docker-compose up --buildThat's it! The API will be available at:
- π API: http://localhost:5034
- π Swagger: http://localhost:5034/swagger
docker pull ghcr.io/jakubpatkowski/todotaskapi:latestClick to expand local setup instructions
Prerequisites:
- .NET SDK 8.0
- PostgreSQL 15+
Configure database β Create appsettings.Development.json in src/TodoTaskAPI.API/:
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=TodoDb;Username=postgres;Password=postgres"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Information"
}
}
}Run the application:
dotnet run --project src/TodoTaskAPI.API| File | Purpose |
|---|---|
docker-compose.yml |
Production-ready configuration |
docker-compose.override.yml |
Development overrides (auto-merged by Docker) |
docker-compose.test.yml |
Testing with isolated database |
docker-compose.dcproj |
Visual Studio Docker Compose project |
# Development (auto-merges override)
docker-compose up --build
# Run tests in containers
docker-compose -f docker-compose.test.yml up --buildThe project includes comprehensive test coverage with both unit and integration tests.
Integration tests use Testcontainers to spin up a real PostgreSQL database:
// Real PostgreSQL in Docker
_dbContainer = new PostgreSqlBuilder()
.WithImage("postgres:latest")
.WithDatabase("TodoDb")
.WithUsername("postgres")
.WithPassword("postgres")
.Build();Tests execute through WebApplicationFactory for full HTTP stack testing:
// Real HTTP requests through the entire pipeline
var response = await _client.PostAsJsonAsync("/api/todos", newTodo);# Run all tests
dotnet test TodoTaskApi.sln
# Run unit tests only
dotnet test tests/TodoTaskAPI.UnitTests/TodoTaskAPI.UnitTests.csproj
# Run integration tests only
dotnet test tests/TodoTaskAPI.IntegrationTests/TodoTaskAPI.IntegrationTests.csproj
# Run with coverage
dotnet test TodoTaskApi.sln --collect:"XPlat Code Coverage"
# Run with verbose output
dotnet test TodoTaskApi.sln --verbosity normal| Category | Description | Database |
|---|---|---|
| Unit Tests | Service logic, DTOs, middleware | Mocked |
| Integration Tests | Full API endpoint testing | Real PostgreSQL (Testcontainers) |
| Performance Tests | Rate limiting under load | Real PostgreSQL |
| Health Tests | Database connectivity, multi-client | Real PostgreSQL |
GitHub Actions workflow automatically runs on every push and PR:
jobs:
build-and-test:
services:
postgres: # Real PostgreSQL service container
image: postgres:latest
steps:
- Build solution
- Run Unit Tests with Coverage
- Run Integration Tests
- Upload Coverage to Codecov| Workflow | Description | Trigger |
|---|---|---|
| CI | Build, test, coverage | Push/PR to main |
| CodeQL | Security scanning | Push/PR + weekly |
| Docker | Build & push to GHCR | Push to main + tags |
| Release Drafter | Auto release notes | PR merges |
View workflow runs: Actions
- CodeQL Analysis β Automated security scanning on every push and weekly
- Dependabot β Automatic dependency updates for NuGet, Docker, and GitHub Actions
- Rate Limiting β Token bucket algorithm protection against API abuse
Entity Framework Core handles all database operations with automatic migrations:
- Migrations applied automatically on startup
- Seed data for development environment
- Code-first approach with fluent configuration
No manual SQL scripts required!
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License β see the LICENSE file for details.
Made with β€οΈ by Jakub Patkowski

