A simple REST API for managing tasks, built with FastAPI, PostgreSQL, and Docker. This project demonstrates modern Python backend development with async programming, database integration, and containerization.
- β CRUD Operations: Create, Read, Update, Delete tasks
- β Async Programming: Built with FastAPI's async/await for high performance
- β PostgreSQL Database: Persistent data storage with proper schema
- β Docker & Docker Compose: Easy setup and deployment
- β Type Safety: Pydantic models for request/response validation
- β Error Handling: Proper HTTP status codes and error messages
- β
API Documentation: Auto-generated Swagger UI at
/docs
βββββββββββββββ ββββββββββββββββ
β FastAPI βββββββββββ PostgreSQL β
β (Port 8001)β β (Port 5433) β
βββββββββββββββ ββββββββββββββββ
β
Docker Container
Tech Stack:
- Framework: FastAPI 0.104.1
- Database: PostgreSQL 15 (Alpine)
- ORM: SQLAlchemy 2.0 with async support
- Async Driver: asyncpg
- Server: Uvicorn
- Containerization: Docker & Docker Compose
.
βββ main.py # FastAPI application & endpoints
βββ models.py # SQLAlchemy ORM models & Pydantic schemas
βββ database.py # Database connection & session management
βββ requirements.txt # Python dependencies
βββ Dockerfile # FastAPI container configuration
βββ docker-compose.yml # Multi-container setup
βββ .env.example # Example environment variables
βββ .gitignore # Git ignore rules
βββ README.md # This file
- Docker & Docker Compose
- Git (optional, for version control)
- Clone the repository (if you haven't already):
git clone https://github.com/YourUsername/Personal-Task-Manager-API.git
cd Personal-Task-Manager-API- Start the services:
docker compose up --buildYou should see:
β
Container task_manager_db Running
β
Container task_manager_app Running
β
Application startup complete
- Test the API:
curl http://localhost:8001/Expected response:
{"message":"Task Manager API is running! π"}GET /Returns: {"message":"Task Manager API is running! π"}
POST /tasks
Content-Type: application/json
{
"title": "Learn Docker",
"description": "Understand containers and Docker Compose",
"status": "in_progress"
}Response (201 Created):
{
"id": 1,
"title": "Learn Docker",
"description": "Understand containers and Docker Compose",
"status": "in_progress",
"created_at": "2026-05-21T20:30:00+00:00"
}GET /tasksResponse (200 OK):
[
{
"id": 1,
"title": "Learn Docker",
"description": "Understand containers and Docker Compose",
"status": "in_progress",
"created_at": "2026-05-21T20:30:00+00:00"
},
{
"id": 2,
"title": "Learn FastAPI",
"description": "Build REST APIs",
"status": "pending",
"created_at": "2026-05-21T20:35:00+00:00"
}
]GET /tasks/1Response (200 OK):
{
"id": 1,
"title": "Learn Docker",
"description": "Understand containers and Docker Compose",
"status": "in_progress",
"created_at": "2026-05-21T20:30:00+00:00"
}PATCH /tasks/1
Content-Type: application/json
{
"status": "completed"
}Response (200 OK):
{
"id": 1,
"title": "Learn Docker",
"description": "Understand containers and Docker Compose",
"status": "completed",
"created_at": "2026-05-21T20:30:00+00:00"
}DELETE /tasks/1Response (200 OK):
{"message":"Task 1 deleted successfully"}FastAPI auto-generates interactive API docs:
- Swagger UI: http://localhost:8001/docs
- ReDoc: http://localhost:8001/redoc
You can test all endpoints directly from these interfaces!
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description VARCHAR,
status VARCHAR(50) NOT NULL DEFAULT 'pending',
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);Columns:
id: Auto-incrementing primary keytitle: Task title (required, max 255 chars)description: Detailed description (optional)status: One ofpending,in_progress,completedcreated_at: Timestamp when task was created
All endpoints use async def to handle multiple requests simultaneously without blocking. This makes the API fast and efficient.
@app.get("/tasks")
async def get_all_tasks(session: AsyncSession = Depends(get_session)):
result = await session.execute(select(TaskDB))
return result.scalars().all()Depends(get_session) automatically provides a database session to each endpoint:
async def get_task(task_id: int, session: AsyncSession = Depends(get_session)):
# session is automatically provided by FastAPI
result = await session.execute(select(TaskDB).where(TaskDB.id == task_id))Request/response validation happens automatically:
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
status: str = "pending"FastAPI validates the JSON and converts it to a Python object.
Define tables as Python classes:
class TaskDB(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
# ...The API returns appropriate HTTP status codes:
| Status | Meaning | Example |
|---|---|---|
| 200 | Success | GET, PATCH, DELETE worked |
| 201 | Created | POST created new task |
| 404 | Not Found | Task ID doesn't exist |
| 422 | Validation Error | Invalid request body |
| 500 | Server Error | Database connection failed |
curl -X POST http://localhost:8001/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Task 1","status":"pending"}'
curl -X POST http://localhost:8001/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Task 2","status":"in_progress"}'
curl -X POST http://localhost:8001/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Task 3","status":"completed"}'curl http://localhost:8001/tasks | jqcurl -X PATCH http://localhost:8001/tasks/2 \
-H "Content-Type: application/json" \
-d '{"status":"completed","title":"Updated Task 2"}'curl -X DELETE http://localhost:8001/tasks/3This project teaches:
- Docker: Containerization and Docker Compose
- FastAPI: Building modern REST APIs in Python
- PostgreSQL: Relational databases and SQL
- SQLAlchemy: Python ORM for database operations
- Async Programming: asyncio and async/await
- API Design: RESTful principles, status codes, error handling
Create a .env file based on .env.example:
DATABASE_URL=postgresql+asyncpg://taskuser:taskpass@db:5432/taskdb
ENVIRONMENT=development
If port 8001 or 5433 is already in use, modify docker-compose.yml:
ports:
- "8002:8000" # Change 8002 to another portMake sure Docker Desktop (or OrbStack on Mac) is running.
Check Docker logs:
docker compose logs db
docker compose logs webRebuild the image:
docker compose down
docker compose up --build- Add user authentication (JWT tokens)
- Add task filtering and sorting
- Add pagination for large task lists
- Add task categories/tags
- Add due dates and reminders
- Add unit tests
- Add CI/CD pipeline (GitHub Actions)
- Deploy to cloud (AWS, Heroku, Railway)
This project is open source and available under the MIT License.
Tejas Malhotra
- Email: tejas.malhotra.14@gmail.com
- GitHub: ApparentlyTejas
- (https://github.com/ApparentlyTejas)
Happy coding! π If you found this helpful, please star the repository!