Skip to content

Production-ready REST API for todo management built with .NET 8, Clean Architecture, Testcontainers, Docker, and comprehensive testing

License

Notifications You must be signed in to change notification settings

JakubPatkowski/TodoTaskApi

Repository files navigation

πŸ“‹ Todo Task API

.NET Build and Test codecov CodeQL Docker Tests

Docker License: MIT Release

.NET PostgreSQL

πŸ“Š Code Coverage

Codecov Tree

Production-ready REST API for todo management built with .NET 8, Clean Architecture, Testcontainers, Docker, and comprehensive testing.

πŸ“Έ Screenshoots

Swagger Get Frontend Main Page

Swagger Frontend Main Page

πŸ† Highlights

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

✨ Features

  • 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

πŸ› οΈ Tech Stack

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

πŸ—οΈ Architecture

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         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

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/

πŸ“– API Endpoints

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

Example Requests

# 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}'

πŸš€ Quick Start

Using Docker (Recommended)

# Clone the repository
git clone https://github.com/JakubPatkowski/TodoTaskApi
cd TodoTaskApi

# Build and run with Docker Compose
docker-compose up --build

That's it! The API will be available at:

🐳 Pull from GitHub Container Registry

docker pull ghcr.io/jakubpatkowski/todotaskapi:latest

Local Development

Click to expand local setup instructions

Prerequisites:

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

🐳 Docker Configuration

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 --build

πŸ§ͺ Testing

The project includes comprehensive test coverage with both unit and integration tests.

Test Infrastructure

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);

Running Tests

# 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

Test Categories

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

πŸ”§ CI/CD Pipeline

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

Workflows

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

πŸ”’ Security

  • 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

πŸ—„οΈ Database

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!

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.


Made with ❀️ by Jakub Patkowski