A REST API for managing tasks, built with FastAPI, Pydantic, SQLite, and pytest.
The project demonstrates a complete CRUD workflow:
HTTP request
→ FastAPI endpoint
→ Pydantic validation
→ SQLite database operation
→ response model validation
→ JSON response
- Create tasks
- Read all tasks
- Read a task by ID
- Partially update tasks
- Delete tasks
- Persistent SQLite storage
- Request and response validation with Pydantic
- Automatic interactive API documentation
- Isolated tests using temporary databases
- Python
- FastAPI
- Pydantic
- SQLite
- Uvicorn
- pytest
- FastAPI TestClient
task-manager-api/
├── data/
│ └── tasks.db
├── src/
│ └── task_manager_api/
│ ├── __init__.py
│ ├── api.py
│ ├── database.py
│ └── models.py
├── tests/
│ ├── conftest.py
│ ├── test_api_post.py
│ ├── test_api_get.py
│ ├── test_api_patch.py
│ ├── test_api_delete.py
│ └── test_database.py
├── pyproject.toml
├── README.md
├── .gitignore
└── requirements.txt
A task contains the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | generated | Unique identifier created by SQLite |
title |
string | yes | Non-empty task title |
description |
string or null | no | Optional task description |
due_date |
date or null | no | Optional due date in YYYY-MM-DD format |
Example:
{
"id": 1,
"title": "List of products",
"description": "Milk, eggs, bread",
"due_date": "2026-07-12"
}Clone the repository and enter the project directory:
git clone https://github.com/herdlich/task-manager-api.git
cd task-manager-apiCreate and activate a virtual environment:
python -m venv .venvLinux and macOS:
source .venv/bin/activateWindows PowerShell:
.venv\Scripts\Activate.ps1Install the project and its dependencies declared in pyproject.toml:
pip install -e .Run Uvicorn from the project root:
uvicorn task_manager_api.api:app --reloadThe API will be available at:
http://127.0.0.1:8000
Interactive Swagger documentation:
http://127.0.0.1:8000/docs
Alternative ReDoc documentation:
http://127.0.0.1:8000/redoc
| Method | Endpoint | Description | Success status |
|---|---|---|---|
GET |
/health |
Check API availability | 200 |
POST |
/tasks |
Create a task | 201 |
GET |
/tasks |
Return all tasks | 200 |
GET |
/tasks/{task_id} |
Return one task | 200 |
PATCH |
/tasks/{task_id} |
Partially update a task | 200 |
DELETE |
/tasks/{task_id} |
Delete and return a task | 200 |
A request for a missing task returns:
{
"detail": "No task found"
}with status code 404.
Invalid request data returns status code 422.
curl -X POST "http://127.0.0.1:8000/tasks" \
-H "Content-Type: application/json" \
-d '{
"title": "List of products",
"description": "Milk, eggs, bread",
"due_date": "2026-07-12"
}'Response:
{
"id": 1,
"title": "List of products",
"description": "Milk, eggs, bread",
"due_date": "2026-07-12"
}curl "http://127.0.0.1:8000/tasks"curl "http://127.0.0.1:8000/tasks/1"Only fields included in the request are changed:
curl -X PATCH "http://127.0.0.1:8000/tasks/1" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated product list"
}'An empty JSON object is accepted and leaves the task unchanged:
{}The title field may be omitted during an update, but explicitly sending "title": null is rejected.
curl -X DELETE "http://127.0.0.1:8000/tasks/1"The endpoint returns the deleted task.
titleis required when creating a task.- Leading and trailing whitespace is removed from
title. - An empty or whitespace-only title is rejected.
due_datemust use the ISO formatYYYY-MM-DD.descriptionanddue_datemay benull.- During partial updates, omitted fields remain unchanged.
- During partial updates,
title: nullis rejected.
The application uses SQLite.
The database file is stored at:
data/tasks.db
SQLite generates task IDs automatically. Dates are stored as ISO-formatted text, and optional values are stored as SQL NULL.
The database layer is separated from the HTTP layer:
api.pyhandles requests, responses, and HTTP errors.database.pycontains SQL and database operations.models.pycontains request and response models.
Run the complete test suite:
pytest -qThe tests cover:
- successful CRUD operations
- missing-task
404responses - request validation
- empty and whitespace-only titles
- invalid dates
title: nullduring updates- empty partial updates
- SQLite inserts and reads
- nullable dates
- empty task lists
- reading multiple tasks
- response data integrity
API tests use an isolated SQLite database created inside pytest's tmp_path. The application database is not modified during tests.
This project intentionally uses direct SQLite queries to demonstrate the complete request-to-database flow without hiding it behind an ORM.
Potential future improvements include:
- task completion status
- filtering and pagination
- SQLAlchemy
- PostgreSQL
- database migrations
- Docker
- authentication
- structured logging
- deployment
This project is intended for educational and portfolio use.